Mr.Clutch


私信TA

用户名:uq_63396757599

访问量:5210

签 名:

等  级
排  名 2451
经  验 2196
参赛次数 0
文章发表 20
年  龄 0
在职情况 学生
学  校
专  业

  自我简介:

解题思路:

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

  评论区