题目不太记得清了,大意是有个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;
}