双路DP:洛谷P1006 传纸条

题目

传送门

思路

经典的双路DP,问题看成有两个人,从左上走到右下,除了起点/重点外,路径不重合,求两个人经过的点的权值之和最大值

设f [p] [i] [j]表示当前走了p步,第一个人走到第i行,第二个人走到第j行,除起点外路径不重合的条件下,权值之和的最大值

显然,通过p,i,j,我们是可以求出当点两个人的坐标的(因为只能向右或向下走):(i,p-i+1),(j,p-j+1)

则状态转移:

[f[p][i][j]=max{^{max{^{f[p-1][i][j]}_{f[p-1][i][j-1]} }_{max{^{f[p-1][i-1][j]}_{f[p-1][i-1][j-1]}}+map[i][p-i+1]+map[j][p-j+1] ]

特别地,当两个点重合时(i==j)

[f[p][i][j]=-∞ ]

代码

#include <iostream>
#include <cstdio>
using namespace std;
inline int maxx(int a , int b){
	return a >b ? a : b;
}
int n , m;
int map[60][60];
int f[120][60][60];

int main() {
	scanf("%d %d" , &n , &m);
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j <= m ; j++)
			scanf("%d" , &map[i][j]);
	f[1][1][1] = map[1][1];
	for(int p = 2 ; p <= n + m - 1 ; p++)
		for(int i = 1 ; i <= n && i <= p ; i++)
			for(int j = 1 ; j <= n && j <= p ; j++) {
				if(i == 1 && j == 1)continue;
				f[p][i][j] = maxx(maxx(f[p - 1][i][j] , f[p - 1][i][j - 1]) , maxx(f[p - 1][i - 1][j] , f[p - 1][i - 1][j - 1]));
				f[p][i][j] += map[i][p - i + 1] + map[j][p - j + 1];
				if(i == j && p != n + m - 1)//如果到了右下角,两个人是可以重合的
					f[p][i][j] = -(1 << 29);
			}
	cout << f[n + m - 1][n][n];
	return 0;
}
/*
8 6
0 94 11 25 24 51 
15 13 39 67 97 19 
76 12 33 99 18 92 
35 74 0 95 71 39 
33 39 32 37 45 57 
71 95 5 71 24 86 
8 51 54 74 24 75 
70 33 63 29 99 0 

1382
*/
原文地址:https://www.cnblogs.com/dream1024/p/13957866.html