计蒜客 蒜头君的城堡之旅(DP)

蒜头君的城堡之旅

#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;
}



猜你喜欢

转载自blog.csdn.net/ccshijtgc/article/details/80893181
今日推荐