题目不太记得清了,大意是有个MXN的棋盘,然后每个格子上有一个价值,需要从左上角走到右下角再走回来,但每个格子只能走一次,请问来回的最大收获是多少。
找了个NOIP的原题:
题目链接: http://soj.me/1767
考查从 (1,1)到(m,n)找两条不相交的路径使得它们的权值和最大。
法1:动态规划
设 f [ k ][ i ][ j ] 表示第 k 步,第 1 条路径走到第 i 行,第 2 条路径走到第 j 行的最大权值和。
状态转移方程:
f [ k ][ i ][ j ] = max { f [ k - 1 ][ i - 1 ][ j ], f [ k - 1 ][ i ][ j - 1 ], f [ k - 1 ][ i ][ j ], f [ k - 1 ][ i - 1 ][ j - 1 ] } + map[ i ][ k - i ] + map[ j ][ k - j ]
( 2 <= k <= m + n, 1 <= i, j <= min { m, k - 1 }, i != j )
注意起始两个格子的价值是没有计算的。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int f[120][60][60]; int map[60][60]; int max(int a, int b, int c, int d) { int max1, max2; max1 = max(a, b); max2 = max(c, d); return max(max1, max2); } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int m, n; while (scanf("%d%d", &m, &n) != EOF) { for (int i = 1; i <= m; i ++) { for (int j = 1; j <= n; j ++) { scanf("%d", &map[i][j]); } } memset(f, 0, sizeof(f)); for (int k = 2; k <= m + n; k ++) { for (int i = 1; i <= m && i <= k - 1; i ++) { for (int j = 1; j <= m && j <= k - 1; j ++) { if (k != m + n && i == j) continue; f[k][i][j] = max(f[k - 1][i - 1][j], f[k - 1][i][j - 1], f[k - 1][i][j], f[k - 1][i - 1][j - 1]) + map[i][k - i] + map[j][k - j]; } } } printf("%d\n", f[m + n][m][m]); } return 0; }