方格取数(四维dp)

链接:https://ac.nowcoder.com/acm/problem/16759
来源:牛客网

题目描述
设有N*N的方格图(N ≤ 10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入描述:
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出描述:
只需输出一个整数,表示2条路径上取得的最大的和。
示例1
输入
复制
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

这是参考某位大佬的
一开始的思路是这样的,安排两个人走,第一个人走的时候保证他拿的是最大化的,并且将走过的路全部置为0,再让第二个人走,保证最大,将两个人走过的数全部加起来

但是这样不对
正解将一开始想的二维dp翻一倍,变成思维的,i1,j1表示第一个人的位置,i2,j2表示第二个人的位置,向下找子问题,就能找到四种情况。
第一种情况:两个人都从上方走到现在的位置(dp[i1-1][j1][i2-1][j2])
第二种情况:两个人都从左边走到现在的位置(dp[i1][j1-1][i2][j2-1])
第三种情况:第一个人从上方走来,第二个人从左边走来(dp[i1-1][j1][i2][j2-1])
第四种情况:第一个人从左边走来,第二个人从上方走来(dp[i1][j1-1][i2-1][j2])
显然,两个人是同时走的,所以我们能够推出i1+j1==i2+j2

最后要考虑的就是取数的时候怎么取,那么容易想到分两种情况,第一种情况是两个人通过最后这一步走法,走到的位置相同,那么取的数肯定是a[i1][j1] or a[i2][j2](都是同一个数),第二种情况是两个人通过最后这一步走法,走到的位置不同,那么取的数肯定是a[i1][j1] and a[i2][j2]

通过这样的递推,就完成了百分之九十了,万事俱备只欠东风。
由于题目说两个人都到达右下角,那么两个人的坐标肯定都为(n,n)
所以答案为dp[n][n][n][n]

分割线————————————————

我的理解
问题 走两次走到(n,n)的最大值的和
子问题 2人同时走,走到(i,j),(k,l)的最大值的和
故状态转移方程

d(i, j, k, l)表示1走到(i,j),2走到(k,l)时的和的最大值
d(i, j, k, l)=max( d(i-1,j,k-1, l) , d(i-1,j,k,l-1),d(i,j-1,k-1, l),d(i,j-1,k, l-1) ) +a(i,j)+a(k,l) (i+j=k+l)
d(i, j, k, l)=max( d(i-1,j,k-1, l) , d(i-1,j,k,l-1),d(i,j-1,k-1, l),d(i,j-1,k, l-1) ) +a(i,j) (i=k,j=l)

初始条件 可以不用初始化

我的代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL maxn=20;
LL a[maxn][maxn];
LL dp[maxn][maxn][maxn][maxn];
LL n;



int main(){
    
    
	cin>>n;
	LL x,y,w;
	memset(dp,0,sizeof dp);
	while(~scanf("%lld%lld%lld",&x,&y,&w)&&(x+y+w)){
    
    
        a[x][y]=w;
    }
		for(LL i=1;i<=n;i++){
    
    
			for(LL j=1;j<=n;j++){
    
    
				for(LL k=1;k<=n;k++){
    
    
					for(LL l=1;l<=n;l++){
    
    
					if(i+j==k+l)dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]),max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]))+a[i][j]+a[k][l];
                    if(i==k&&j==l){
    
    
                        dp[i][j][k][l]-=a[k][l];
                    }
						
					}
				}
			}
		}
		cout<<dp[n][n][n][n];
	
	return 0;
}
 


 

加油~~~~

猜你喜欢

转载自blog.csdn.net/peizhecpp/article/details/106725786
今日推荐