解题思路:
动态规划,看起来像是蓝桥杯经典的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分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复