洛谷 P1006 传纸条(NOIP2008提高组第三题)

本以为一来一回两遍DP
然而这样有后效性

所以改成了

四维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⊙)…

你可能感兴趣的:(洛谷)