SenseTime Ace Coder Challenge 暨 商汤在线编程挑战赛*A:双人取数(DP)

有一款双人游戏,游戏的地图是一张 n×m 的平面,其中玩家 A 从地图的左上角出发,通过向右和向下走的方式走到右下角,玩家 B 从右上角出发,通过向左和向下的方式走到左下角(每次只能走到上下左右相邻的至多四个格子)。

每个格子有一个分数,玩家走到格子上就会获得这个分数,当一个玩家得到这个分数后,格子的分数就会自动变为 0。游戏最后的得分是两个人获得分数的总和。

即使两个人同时进入一个格子,这个格子上的分数也只会被计入一次。

现在希望你帮忙计算出,这个游戏能获得的最高分是多少。

输入格式

输入第一行一个整数 T。表示测试数据组数。

接下来输入 T 组数据。每组数据按照下面的规则输入。

对于每组数据第一行输入两个整数 nm,代表游戏地图的长和宽。

然后接下来的 n 行每行输入 m 个整数,代表地图上每个格子的分数。

1T153n,m1000

每个格子分数绝对值 1000

输出格式

对于第i组数据,输出格式形如"Case #i: x"(输出不含引号),其中x表示该组数据对应的游戏最高分。

样例输入

2
3 4
3 2 2 3
2 2 3 2
1 1 1 1
3 3
-1 -1 -1
-1 -1 -1
-1 -1 -1

样例输出

Case #1: 22
Case #2: -7
思路:路径公共部分只会算一次,分别预处理从矩阵四个顶点走到某个定点的最大元素之和,然后枚举公共路径。公共路径只会是一条横线或一条竖线或某个点,按顺序枚举公共路径的一个端点,用之前的信息选出最优的另一个端点。具体细节还请看代码(可能写得比较丑。。)。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3+10;
const double PI=acos(-1.0);
typedef long long ll;
int a[MAX][MAX];
int lu[MAX][MAX];//记录从左上角出发到达(i,j)的最优值
int ld[MAX][MAX];//记录从左下角出发到达(i,j)的最优值
int ru[MAX][MAX];//记录从右上角出发到达(i,j)的最优值
int rd[MAX][MAX];//记录从右下角出发到达(i,j)的最优值
int L[MAX][MAX];//记录以(i,j)为公共横线的左端点的路径的最优值
int D[MAX][MAX];//记录以(i,j)为公共竖线的上端点的路径的最优值
int n,m;
void show(int p[][1010])
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)printf("%d ",p[i][j]);cout<<endl;
    }
    cout<<endl;
}
int main()
{

    int T,cas=1;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(lu,0,sizeof lu);
        memset(ru,0,sizeof ru);
        memset(rd,0,sizeof rd);
        memset(ld,0,sizeof ld);
        memset(L,0,sizeof L);
        memset(D,0,sizeof D);
        memset(a,0,sizeof a);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
        }
        for(int i=1;i<=n;i++)       //预处理lu[i][j]
        {
            for(int j=1;j<=m;j++)
            {
                lu[i][j]=-1e9;
                if(i==1&&j==1)lu[i][j]=a[i][j];
                if(i>1)lu[i][j]=max(lu[i][j],lu[i-1][j]+a[i][j]);
                if(j>1)lu[i][j]=max(lu[i][j],lu[i][j-1]+a[i][j]);
            }
        }
        for(int i=n;i>=1;i--)       //预处理ld[i][j]
        {
            for(int j=1;j<=m;j++)
            {
                ld[i][j]=-1e9;
                if(i==n&&j==1)ld[i][j]=a[i][j];
                if(i<n)ld[i][j]=max(ld[i][j],ld[i+1][j]+a[i][j]);
                if(j>1)ld[i][j]=max(ld[i][j],ld[i][j-1]+a[i][j]);
            }
        }
        for(int i=1;i<=n;i++)       //预处理ru[i][j]
        {
            for(int j=m;j>=1;j--)
            {
                ru[i][j]=-1e9;
                if(i==1&&j==m)ru[i][j]=a[i][j];
                if(i>1)ru[i][j]=max(ru[i][j],ru[i-1][j]+a[i][j]);
                if(j<m)ru[i][j]=max(ru[i][j],ru[i][j+1]+a[i][j]);
            }
        }
        for(int i=n;i>=1;i--)       //预处理rd[i][j]
        {
            for(int j=m;j>=1;j--)
            {
                rd[i][j]=-1e9;
                if(i==n&&j==m)rd[i][j]=a[i][j];
                if(i<n)rd[i][j]=max(rd[i][j],rd[i+1][j]+a[i][j]);
                if(j<m)rd[i][j]=max(rd[i][j],rd[i][j+1]+a[i][j]);
            }
        }
        for(int i=1;i<=n;i++)       //预处理L[i][j]
        {
            for(int j=m;j>=1;j--)
            {
                if(j==m)L[i][j]=rd[i+1][j]+ru[i-1][j]+a[i][j];
                else
                {
                    L[i][j]=L[i][j+1]+a[i][j];
                    if(i>1&&i<n)
                    {
                        L[i][j]=max(L[i][j],ru[i-1][j]+max(rd[i+1][j],rd[i][j+1])+a[i][j]);
                        L[i][j]=max(L[i][j],rd[i+1][j]+max(ru[i-1][j],ru[i][j+1])+a[i][j]);
                    }
                    else if(i>1&&i==n)L[i][j]=max(L[i][j],ru[i-1][j]+rd[i][j+1]+a[i][j]);
                    else if(i==1&&i<n)L[i][j]=max(L[i][j],ru[i][j+1]+rd[i+1][j]+a[i][j]);
                }
            }
        }
        for(int j=1;j<=m;j++)       //预处理D[i][j]
        {
            for(int i=n;i>=1;i--)
            {
                if(i==n)D[i][j]=ld[i][j-1]+rd[i][j+1]+a[i][j];
                else
                {
                    D[i][j]=D[i+1][j]+a[i][j];
                    if(j>1&&j<m)
                    {
                        D[i][j]=max(D[i][j],ld[i][j-1]+max(rd[i][j+1],rd[i+1][j])+a[i][j]);
                        D[i][j]=max(D[i][j],rd[i][j+1]+max(ld[i][j-1],ld[i+1][j])+a[i][j]);
                    }
                    else if(j>1&&j==m)D[i][j]=max(D[i][j],ld[i][j-1]+rd[i+1][j]+a[i][j]);
                    else if(j==1&&j<m)D[i][j]=max(D[i][j],rd[i][j+1]+ld[i+1][j]+a[i][j]);
                }
            }
        }
        int ans=-1e9;
        for(int i=1;i<=n;i++)       //枚举横线左端点并更新答案
        {
            for(int j=1;j<m;j++)
            {
                if(j==1)ans=max(ans,max(lu[i-1][j]+ld[i][j],lu[i][j]+ld[i+1][j])+L[i][j+1]);
                else
                {
                    if(i>1&&i<n)
                    {
                        ans=max(ans,ld[i+1][j]+lu[i][j]+L[i][j+1]);
                        ans=max(ans,lu[i-1][j]+ld[i][j]+L[i][j+1]);
                    }
                    else if(i>1&&i==n)ans=max(ans,ld[i][j]+lu[i-1][j]+L[i][j+1]);
                    else if(i==1&&i<n)ans=max(ans,ld[i+1][j]+lu[i][j]+L[i][j+1]);
                }
            }
        }
        for(int j=1;j<=m;j++)       //枚举竖线上端点并更新答案
        {
            for(int i=1;i<n;i++)
            {
                if(i==1)ans=max(ans,max(lu[i][j-1]+ru[i][j],lu[i][j]+ru[i][j+1])+D[i+1][j]);
                else
                {
                    if(j>1&&j<m)
                    {
                        ans=max(ans,lu[i][j-1]+ru[i][j]+D[i+1][j]);
                        ans=max(ans,ru[i][j+1]+lu[i][j]+D[i+1][j]);
                    }
                    else if(j>1&&j==m)ans=max(ans,lu[i][j-1]+ru[i][j]+D[i+1][j]);
                    else if(j==1&&j<m)ans=max(ans,lu[i][j]+ru[i][j+1]+D[i+1][j]);
                }
            }
        }
        for(int i=2;i<n;i++)       //枚举只有一个公共交点时的答案
        {
            for(int j=2;j<m;j++)
            {
                ans=max(ans,lu[i][j-1]+ld[i+1][j]+ru[i-1][j]+rd[i][j+1]+a[i][j]);
                ans=max(ans,lu[i-1][j]+ld[i][j-1]+ru[i][j+1]+rd[i+1][j]+a[i][j]);
            }
        }
        printf("Case #%d: %d\n",cas++,ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/mitsuha_/article/details/80197562
ACE