fzu - 牧场物语-2234 - 动态规划

问题

Problem Description

小茗同学正在玩牧场物语。该游戏的地图可看成一个边长为n的正方形。
小茗同学突然心血来潮要去砍树,然而,斧头在小茗的右下方。

小茗是个讲究效率的人,所以他会以最短路程走到右下角,然后再返回到左上角。并且在路上都会捡到/踩到一些物品,比如说花朵,钱和大便等。

物品只能被取最多一次。位于某个格子时,如果格子上还有物品,就一定要取走。起点和终点上也可能有物品。
每种物品我们将为其定义一个价值,当然往返之后我们取得的物品的价值和越大越好。但是小茗同学正在认真地玩游戏,请你计算出最大的价值和。

Input

多组数据(<=10),处理到EOF。
第一行输入正整数N(N≤100),表示正方形的大小。
接下来共N行,每行N个整数Ai,j(|Ai,j|≤10^9),表示相应对应位置上物品的价值。值为0表示没有物品。

Output

每组数据输出一个整数,表示最大价值和。

Sample Input

2
11 14
16 12

Sample Output

53

Source

福州大学第十三届程序设计竞赛F题

题解

思路

不难看出,可转化为从(1,1)到(n,n)走两次所经过的方格的和最多能有多少
经分析可知,每个方格的横坐标纵坐标之和就是所经过的时间,
x和y和t之间有关系,t+1=x+y,显然可以减掉两维了
dp[t][i][j]表示走了时间t,两个人的横坐标分别为i,j;那么他们的纵坐标便为t-i+1,t-j+1;
同时,如果两个人走到一个点,他们所经过的时间必定相同
所以转移方程为dp[t][i][j]=max1(dp[t-1][i][j],dp[t-1][i-1][j],dp[t-1][i][j-1],dp[t-1][i-1][j-1])+(i==j?a[i][t+1-i]:(a[i][t+1-i]+a[j][t+1-j])));

代码

#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;

const LL INF=1e12;
LL dp[2][105][105];
LL a[105][105];
int main()
{
    LL N;
    while(~scanf("%lld",&N)){
        LL c,k,i,j;
        for(i=0;i<=N;i++){
            for(j=0;j<=N;j++){
                dp[0][i][j]=dp[1][i][j]=-INF;
                if(i>0&&j>0&&i<=N&&j<=N) scanf("%lld",&a[i][j]);
            }
        }
        dp[0][1][1]=a[1][1];
        for(c=0,k=2;k<=2*N-1;k++){
            c^=1;
            for(i=1;i<=N;i++){
                for(j=1;j<=N;j++){
                    if(k+1-i>0&&k+1-j>0&&k+1-i<=N&&k+1-j<=N){
                        dp[c][i][j]=max(max(dp[c^1][i][j],dp[c^1][i-1][j-1]),max(dp[c^1][i-1][j],dp[c^1][i][j-1]));
                        if(i==j) dp[c][i][j]+=a[i][k+1-i];
                        else dp[c][i][j]+=a[i][k+1-i]+a[j][k+1-j];
                    }
                }
            }
        }
        printf("%lld\n",dp[c][N][N]);
    }
    return 0;
}

你可能感兴趣的:(C/C++,动态规划)