BSNY设计了一个游戏,在一个n*m的网格中,游戏者要从(1,1)走到(n,m)。每个格子有一个数字,游戏者每到一个格子,得分就会加上格子上的分数,初始得分为0。但这个分数有正有负:
如果是正数,游戏者加上这个分数,但此时格子的分数会变相反数,下一次再到这个格子,这个分数就是负数了。
如果是负数,游戏者加上这个分数,之后再到这个格子也一样。
如果是0,不增也不减。
游戏者只能向左,向右,向下移动,不能向上移动。
问,从(1,1)到(n,m)最大可以得多少分?
标签:
BSNY设计了一个游戏,在一个n*m的网格中,游戏者要从(1,1)走到(n,m)。每个格子有一个数字,游戏者每到一个格子,得分就会加上格子上的分数,初始得分为0。但这个分数有正有负:
如果是正数,游戏者加上这个分数,但此时格子的分数会变相反数,下一次再到这个格子,这个分数就是负数了。
如果是负数,游戏者加上这个分数,之后再到这个格子也一样。
如果是0,不增也不减。
游戏者只能向左,向右,向下移动,不能向上移动。
问,从(1,1)到(n,m)最大可以得多少分?
输入n, m
然后输入n*m的矩阵
输出最大得分
【样例说明】
2到-1到3到-1,然后向下走,到1到3到-1到-1
得分为2-1+3-1+1+3-1-1=5
【数据规模和约定】
1<=n, m<=200
-1000<= 格子的分数 <=1000
题解:
因为不能向上走,所以这还是很明显的DP题。
我们定义f[i][j]表示前i行,BSNY在第i行第j个结束(即进入下一行)
那么转移就很简单了,f[i][j]=f[i-1][k]+pre[i][k][j]
pre[i][k][j]表示在第i行,从k点走到j点可以得到的最大值。
现在的难点就在于求这个pre数组了,怎么把它预处理出来呢???
仔细考虑题目,还是能发现一些特性的,比如一个点最多经过3次;
考虑从一个点出发再回到本身,一共有3种情况
1.不走
2.向左或是向右到某个点,再回来
3.先向左走到某个点,再往右走到某个点,最后再向右返回
假如这种情况回来,从k点到j点也是差不多的。
接下来就只剩下把模拟的这个过程的值计算出来了。。
加一下我的方法:
l[i][j]表示第i行的第j个点,向左走并回到原点的最大值。
r[i][j]表示第i行的第j个点,向右走并回到原点的最大值。
中间的片段和也是可以预处理的,注意一下正数走过之后变负这个情况。
#include<stdio.h> #include<iostream> #include<stdlib.h> using namespace std; const int N=205; int n,m,i,j,k,a[N][N],s[N][N],sum[N][N],f[N][N],l[N][N],r[N][N],pre[N][N]; int main() { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&a[i][j]); if(a[i][j]<=0) s[i][j]=s[i][j-1]+a[i][j]*2;else s[i][j]=s[i][j-1]; sum[i][j]=sum[i][j-1]+a[i][j]; } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { if(a[i][j]<=0) l[i][j]=r[i][j]=a[i][j]*2;else l[i][j]=r[i][j]=0; for(k=j+1;k<=m;k++) r[i][j]=max(r[i][j],a[i][k]+s[i][k-1]-s[i][j-1]); for(k=j-1;k>=1;k--) l[i][j]=max(l[i][j],a[i][k]+s[i][j]-s[i][k]); } } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) for(k=j;k<=m;k++) { pre[j][k]=-1e8; pre[j][k]=max(pre[j][k],sum[i][k]-sum[i][j-1]); pre[j][k]=max(pre[j][k],l[i][j]+sum[i][k]-sum[i][j]); pre[j][k]=max(pre[j][k],r[i][k]+sum[i][k-1]-sum[i][j-1]); if(j==k&&a[i][j]<=0) pre[j][k]=max(pre[j][k],l[i][j]+r[i][k]+abs(a[i][j]));else if(j==k&&a[i][j]>0) pre[j][k]=max(pre[j][k],l[i][j]+r[i][k]-abs(a[i][j]));else pre[j][k]=max(pre[j][k],l[i][j]+r[i][k]+sum[i][k-1]-sum[i][j]); pre[k][j]=pre[j][k]; } for(j=1;j<=m;j++) { if(i==1) { f[i][j]=pre[1][j]; continue; } f[i][j]=-1e8; for(k=1;k<=m;k++) f[i][j]=max(f[i][j],f[i-1][k]+pre[k][j]); } } cout<<f[n][m]; return 0; }
标签:
原文地址:http://www.cnblogs.com/lwq12138/p/5647745.html