蓝桥杯 方格取数 Java 闫氏DP分析法和一般方法

先关题目

数字三角形

摘花生

最低通行费

题目描述
设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:

在这里插入图片描述

某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。

在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。

输入格式

第一行为一个整数N,表示 N×N 的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。

行和列编号从 1开始,一行“0 0 0”表示结束。

输出格式

输出一个整数,表示两条路径上取得的最大的和。

数据范围

N≤10

输入样例:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

输出样例:

67

思路

一般方法 四维dp

这个题要求的是走两遍,每次的最大值相加,选过的
方格值为0,一开始我想的是两次二维dp,选过的直接
为0,试验之后发现第二次的dp值为0,才想起来第一
此dp把所有的每格子可能的最大值全算出来了,也就是
说所有的格子都用过。
 于是网上看到的常见的是四维dp,大概思路是这样
 1.想象两个人在这个方格中走,每个人有一条路径,
 总的就是两条路径,dp[i][j][k][l]表示第一个人
 走到(i,j)这个格子的时候第二个走到(k,l)这
 个格子的时候的最大值,答案就是dp[N][N][N][N],
 正好表示第一个人走到(N,N)第二个人也走到了(N,N)
 正好是两条路径;
 
 2. 当两个人走到同一个格子的时候,格子的值只能加
 一次,还有就是第一个人走到(i,j)有两种方法:要
 么从上往下走走到了,要门从左往右走走到了,这样两
 个人就有了“四种”状态,取这四种状态的最大值,就是
 最后的答案;
 

代码


public class Main{
    
    
    public static void main(String[] args) {
    
    
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [][]arr=new int[N+2][N+2];
        for(int i=1;i<=12;i++){
    
    
            int x=input.nextInt();
            int y=input.nextInt();
            arr[x][y]=input.nextInt();

        }
        int [][][][]dp=new int [N+1][N+1][N+1][N+1];
        for(int i=1;i<=N;i++){
    
    
            for(int j=1;j<=N;j++){
    
    
                for(int k=1;k<=N;k++){
    
    
                    for(int l=1;l<=N;l++){
    
    
                    //第一个和第二个都是从下往上来
                    //第一个从上往下第二个从左往右
                        int temp1=Math.max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]);
                    //第一个左往右第二个从上往下
                    //第一个和第二个都是从左往右
                        int temp2=Math.max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]);
                        dp[i][j][k][l]=Math.max(temp1,temp2)+arr[i][j];
                        //坐标不相等时加两次
                        if(i!=k&&j!=l) dp[i][j][k][l]+=arr[k][l];

                    }
                }
            }
        }
        System.out.println(dp[N][N][N][N]);

    }
}

闫氏DP分析法

y总讲的方法将四维DP转化成了三维DP,是因为我们要找的是走两遍可以看成,两个人同时走,同一个格子不能重复选择,所以同时走和分开走最后的结果是一样的。

同时走两条路线它们的横纵坐标的和是相等的,我们把这个和设为K,因此(i,j)就可以表示为(i,K-i) dp[K][i1][i2]表示两个人从(1,1)分别走到(i1,K-i1)和(i2,K-i2)所有路径的最大值 这么说不好理解,直接上两张图
来自y总算法提高课

在这里插入图片描述
然后代码:

import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int [][]arr=new int[N+2][N+2];
        for(int i=1;i<=12;i++){
    
    
            int x=input.nextInt();
            int y=input.nextInt();
            int z=input.nextInt();
            if(x==0&&y==0&&x==0)
            {
    
    
                break;
            }
            else arr[x][y]=z;

        }
        //K表示横纵坐标之和走两条路,同时走所以x+y的值是一定的
        //当i1==i2, 两个在同一格,就只需要加一次
        int dp[][][]=new int [N*2+2][N+1][N+1];
        for(int k=2;k<=N+N;k++){
    
    
            for(int i1=1;i1<=N;i1++){
    
    
                for(int i2=1;i2<=N;i2++){
    
    
                    int j1=k-i1;
                    int j2=k-i2;
                    //看是否符合要求
                    if(j1>=1&&j1<=N&&j2>=1&&j2<=N){
    
    
                        int t=arr[i1][j1];
                        if(i1!=i2)t+=arr[i2][j2];
                        int temp=dp[k][i1][i2];
                        temp=Math.max(temp,dp[k-1][i1-1][i2-1]+t);//上上
                        temp=Math.max(temp,dp[k-1][i1-1][i2]+t);  //下右、
                        temp=Math.max(temp,dp[k-1][i1][i2-1]+t);  //右下
                        temp=Math.max(temp,dp[k-1][i1][i2]+t);    //右右
                        
                        dp[k][i1][i2]=temp;

                    }
                }
            }


        }
        System.out.println(dp[N+N][N][N]);

    }
}

猜你喜欢

转载自blog.csdn.net/qq_44844588/article/details/108219071