双路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
*/