fzu

来源:互联网 发布:国产高达淘宝店 编辑:程序博客网 时间:2024/06/05 19:22

问题

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<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>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;}
原创粉丝点击