#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#define maxn 55
using namespace std;
int n, m;
int map[maxn][maxn];
int f[maxn][maxn][maxn][maxn];
/*
(可以理解为从起点出发的不相交的两条路径)
首先,要注意一个问题:不能先算出去的最大值,再算返回的最大值。
这样可能导致只保证了去的最大值,但没有保证来回之和的最大值。也就是说,
来回的优先级是相同的,但是如果先算去路的最大值就会使得去的优先级高于回的优先级。
容易注意到本题的范围不大,所以可以用一个四维数组:
f[i][j][k][l] 来表示路径1走到 [i][j] 和路径2走到 [k][l] 的和的最优值。
其中,因为走的步数相同,所以 i+j=k+l (可以利用这个等式来把空间和时间复杂度降一级),
不难想到只要当前一步的两条路径没有走到用一个点,
两条路径就不会相交(如果相交,重叠部分的可乐只能领取一次,就不是最优情况)。
最后就不难写出动规方程: f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]),
max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))+map[i][j]+map[k][l];
其中第一部分是求两个路径当前点的两个前趋情况的和的最大值(一共是 2×2 四种情况,所以用了一个 max 套两个 max)。
最最后,因为两条路径在终点还是会交于一点,所以千万不能输出 f[n][m][n][m] ,应该输出 f[n-1][m][n][m-1] 。
*/
int main()
{
//freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
memset(f,0,sizeof(f));
cin >> n >> m;
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
cin >> map[i][j];
}
}
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
for (int k=1; k<=n; k++)
{
if (i==k)
continue;
int l = i + j - k;
f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))
+map[i][j]+map[k][l];
}
}
}
cout << f[n][m-1][n-1][m] << endl;
return 0;
}
计蒜客 蒜头君的城堡之旅(DP)
最新推荐文章于 2019-04-22 21:17:38 发布