行程得分

行程得分

题目描述

BSNY设计了一个游戏,在一个n*m的网格中,游戏者要从(1,1)走到(n,m)。每个格子有一个数字,游戏者每到一个格子,得分就会加上格子上的分数,初始得分为0。但这个分数有正有负:

如果是正数,游戏者加上这个分数,但此时格子的分数会变相反数,下一次再到这个格子,这个分数就是负数了。

如果是负数,游戏者加上这个分数,之后再到这个格子也一样。

如果是0,不增也不减。

游戏者只能向左,向右,向下移动,不能向上移动。

问,从(1,1)到(n,m)最大可以得多少分?

输入

输入n, m

然后输入n*m的矩阵

输出

输出最大得分

样例输入

3
2 -1 3
3 1 -1

样例输出

5

【样例说明】

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

 

posted @ 2016-07-06 18:22  lwq12138  阅读(281)  评论(0编辑  收藏  举报