有一款双人游戏,游戏的地图是一张 n×m 的平面,其中玩家 A 从地图的左上角出发,通过向右和向下走的方式走到右下角,玩家 B 从右上角出发,通过向左和向下的方式走到左下角(每次只能走到上下左右相邻的至多四个格子)。
每个格子有一个分数,玩家走到格子上就会获得这个分数,当一个玩家得到这个分数后,格子的分数就会自动变为 0。游戏最后的得分是两个人获得分数的总和。
即使两个人同时进入一个格子,这个格子上的分数也只会被计入一次。
现在希望你帮忙计算出,这个游戏能获得的最高分是多少。
输入格式
输入第一行一个整数 T。表示测试数据组数。
接下来输入 T 组数据。每组数据按照下面的规则输入。
对于每组数据第一行输入两个整数 n,m,代表游戏地图的长和宽。
然后接下来的 n 行每行输入 m 个整数,代表地图上每个格子的分数。
1≤T≤15,3≤n,m≤1000。
每个格子分数绝对值 ≤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;
}