https://www.luogu.org/problemnew/show/P1006
棋盘dp,化双向为单向:视作从左上往右下传两张纸条且路劲不重复。
又由于只能向右或向下传递,所以两张纸条过程中必定处于同一斜线上,即横纵坐标之和相等。这样就得到了降维的关键。
用dp[s][i][j]表示纸条1走到第i行,纸条2走到第j行时的最大好心程度,那么方程也不难推得了。
#include <cstdio>
#include <algorithm>
#define N 51
using namespace std;
int a[N][N], dp[N * 2][N][N];
int main(void)
{
int i, j, s, m, n, tmp;
scanf("%d%d", &m, &n);
for (i = 1; i <= m; ++i)
for (j = 1; j <= n; ++j)
scanf("%d", &a[i][j]);
for (s = 3; s <= m + n; ++s)
for (i = 1; i <= min(s - 1, m); ++i)
for (j = 1; j <= min(s - 1, m); ++j){
if (i == j) tmp = a[i][s - i];
else tmp = a[i][s - i] + a[j][s - j];
dp[s][i][j] = max(dp[s][i][j], dp[s - 1][i - 1][j - 1]);
dp[s][i][j] = max(dp[s][i][j], dp[s - 1][i][j]);
dp[s][i][j] = max(dp[s][i][j], dp[s - 1][i - 1][j]);
dp[s][i][j] = max(dp[s][i][j], dp[s - 1][i][j - 1]);
dp[s][i][j] += tmp;
}
printf("%d\n", dp[m + n][m][m]);
return 0;
}