解题思路:
动态规划,看起来像是蓝桥杯经典的dfs(试了TLE只有36分= =,因为太多的无效搜索),实则由于两条搜索路径不能相触,必须使用动态规划。
第一步首先是简化题意,两条搜索路径可以看做相同起点、相同终点的搜索,即将另一条搜索路径反序。
首先说一下四维dp,
dp[i][j][x][y]为路径1在(i, j)位置和路径2在(x, y)是最大的权值和
转移方程为dp[i][j][x][y] = max(dp[i-1][j][x-1][y], dp[i-1][j][x][y-1], dp[i][j-1][x-1][y], dp[i][j-1][x][y-1]) + map[i][j] + map[x][y]
因为无论哪个位置,只能尤其上方格子向下走,或者左方格子向右走,而现在又有两个这样的情况要发生,于是就组合出了四种达到dp[i][j][x][y]的方式,取其最大并与当前格子的权值相加即可。
然后是优化后的三维dp,
为了在优化n4的时间复杂度,可以观察路径的规律,可知点(i, j)和点(x, y)的横纵坐标和与当前行走步数有关,且i+j=x+y=k+2,依据此,可替换i,j 或 x,y为k,便可以简化一层循环。注意k的取值,k的最大值为m+n-2,其中在m+n-2值处达到终点。
下述代码中solution1为n4复杂度,solution2为n3复杂度,但显然都可以AC哈哈哈。
注意事项:
边界条件若懒得判断,直接把数组(当我没说)
by the way,如果有佬真的能用dfs解,请叫我围观。
参考代码:
package chapter_200_传纸条; import java.io.*; import java.util.*; // https://www.dotcpp.com/oj/problem1611.html public class Main { static StreamTokenizer cin; static PrintWriter out; static int m; static int n; static int[][] map; public static void main(String[] args) throws IOException{ cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); out = new PrintWriter(new OutputStreamWriter(System.out)); m = nextInt(); // m行 n = nextInt(); // n列 map = new int[100][100]; for(int i = 1; i < m+1; i++){ for(int j = 1; j < n+1; j++) map[i][j] = nextInt(); } out.println(solution2()); out.flush(); out.close(); } static int max(int a, int b, int c, int d){ return Math.max(Math.max(a, b), Math.max(c, d)); } static int solution1(){ // 4维dp int[][][][] dp = new int[m+10][n+10][m+10][n+10]; for(int i = 1; i < m+1; i++){ for(int j = 1; j < n+1; j++){ for(int x = 1; x < m+1; x++){ for(int y = 1; y < n+1; y++){ if(x==i && y==j && ((x < m || y < n))) // 两线路相交 continue; dp[i][j][x][y] = max(dp[i-1][j][x-1][y], dp[i-1][j][x][y-1], dp[i][j-1][x-1][y], dp[i][j-1][x][y-1]) + map[i][j] + map[x][y]; } } } } return dp[m][n][m][n]; } static int solution2(){ // 3维dp i+j=k+2, 如果不想判断边界, 就把数组开大一些 int[][][] dp = new int[100][100][100]; for(int k = 1; k < m+n-1; k++){ for(int i = 1; i < Math.min(k+2, m+1); i++){ for(int x = 1; x < Math.min(k+2, m+1); x++){ if(x == i && k!=m+n-2) // 线路相交 continue; dp[k][i][x] = max(dp[k-1][i][x], dp[k-1][i-1][x], dp[k-1][i][x-1], dp[k-1][i-1][x-1]) + map[i][k+2-i] + map[x][k+2-x]; //equals dp[i][j-1][x][y-1], dp[i-1][j][x][y-1], dp[i][j-1][x-1][y], dp[i-1][j][x-1][y] } } } return dp[m+n-2][m][m]; } static int nextInt() throws IOException{ cin.nextToken(); return (int)cin.nval; } }
0.0分
3 人评分
C语言程序设计教程(第三版)课后习题8.9 (Java代码)浏览:1413 |
打水问题 (C语言代码)浏览:1148 |
C语言程序设计教程(第三版)课后习题6.2 (C语言代码)浏览:1432 |
C语言程序设计教程(第三版)课后习题6.10 (C语言代码)浏览:588 |
C语言程序设计教程(第三版)课后习题1.5 (C语言代码)浏览:368 |
WU-复数求和 (C++代码)浏览:2119 |
蛇行矩阵 (C语言代码)浏览:606 |
C语言程序设计教程(第三版)课后习题5.7 (C语言代码)浏览:645 |
C语言程序设计教程(第三版)课后习题10.2 (C语言代码)浏览:755 |
企业奖金发放 (C语言代码)浏览:2459 |