B. Working out
给n*m的矩阵,每个格子有个数,A从(1,1)出发只能向下或右走,终点为(n,m),B从(n,1)出发只能向上或右走,终点为(1,m)。两个人的速度不一样,走到的格子可以获的该格子的数,两人相遇的格子上的数两个人都不能拿。求A和B能拿到的数的总和的最大值。
n,m<=1000
Sample test(s)
input
3 3
100 100 100
100 1 100
100 100 100
output
800
解题思路:dp。先预处理出每个格子到四个角落格子的路径最大数值,然后枚举两个人相遇的交点格子,枚举A、B的进来和出去方式,求最大值即可。注意边界情况。https://blog.csdn.net/cc_again/article/details/25691925
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1010;
const int INF=0x3f3f3f;
ll dp[4][N][N],a[N][N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%lld",&a[i][j]);
memset(dp,0,sizeof(dp));
//求从点(x,y)到左上、右上、左下、右下四个角能获取的最大和,分别保存在dp[0~3][i][j]
for(int i=1;i<=n;i++){
//从左上角落到(x,y)
for(int j=1;j<=m;j++)
dp[0][i][j]=max(dp[0][i][j-1],dp[0][i-1][j])+a[i][j];
//从右上角落到(x,y)
for(int j=m;j>0;j--)
dp[1][i][j]=max(dp[1][i][j+1],dp[1][i-1][j])+a[i][j];
}
for(int i=n;i>0;i--){
//从左下角落到(x,y)
for(int j=1;j<=m;j++)
dp[2][i][j]=max(dp[2][i][j-1],dp[2][i+1][j])+a[i][j];
//从右下角落到(x,y)
for(int j=m;j>0;j--)
dp[3][i][j]=max(dp[3][i][j+1],dp[3][i+1][j])+a[i][j];
}
//处理边界:方便枚举
for(int i=0;i<=n+1;i++)
for(int j=0;j<4;j++)
dp[j][i][0]=dp[j][i][m+1]=-INF;
for(int i=0;i<=m+1;i++)
for(int j=0;j<4;j++)
dp[j][0][i]=dp[j][n+1][i]=-INF;
ll res=0;
//枚举每个点 ,是相遇的点 (只考虑在一个格子相遇的情况,因此只有两种情况)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
ll val=dp[0][i][j-1]+dp[3][i][j+1]+dp[2][i+1][j]+dp[1][i-1][j];
res=max(res,val);
val=dp[0][i-1][j]+dp[3][i+1][j]+dp[2][i][j-1]+dp[1][i][j+1];
}
printf("%lld\n",res);
}
return 0;
}