解题思路:

动态规划,看起来像是蓝桥杯经典的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.0分

1 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论