本以为一来一回两遍DP
然而这样有后效性
所以改成了
两个点同时出发 路线不重复
f[i][j][p][q]表示一个到(i, j)一个到(p, q)时 最大的好感度
三个判重
Line20 Line28 Line32
一个小剪枝
Line19
//P1006 传纸条
//2017.5.23
#include
using namespace std;
int m, n, s[51][51], f[51][51][51][51], res;
int main(){
cin >> m >> n;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &s[i][j]);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
for (int p = 1; p <= m; p++)
for (int q = 1; q <= n; q++){
if (i + j != p + q) continue; //两点步数一致才计算
if (i == p && j == q && !(i == m && j == n && p == m && q == n)) continue; //除了起点与终点两条线路不可有重合 (起点一定是0 不用算)))
res = 0;
//两个点都从左边来
res = max(res, f[i - 1][j][p - 1][q]);
//一个从左边来 一个从上方来
if (i - 1 != p && j != q - 1) //要判重
res = max(res, f[i - 1][j][p][q - 1]);
//一个从上方来 一个从左边来
if (i != p - 1 && j - 1 != q) //要判重
res = max(res, f[i][j - 1][p - 1][q]);
//两个点都从上方来
res = max(res, f[i][j - 1][p][q - 1]);
f[i][j][p][q] = res + s[i][j] + s[p][q];
// cout << i << ", " << j << " : " << p << ", " << q << " " << f[i][j][p][q] << endl;
}
cout << f[m][n][m][n];
return 0;
}
似乎还有一种方法
可以证明只要重复传给一个人(只算一次分),就一定不是最优解(可能是之一)
因为可以证明0<=f[i][j][k][o]
(⊙o⊙)…