题目大意:给定一个能n×m的表格,每个点上有相应的权值,一个人从(1,1)点出发,目标点为(n,m),另一个人从(n,1)点出发,目标点为(1,m),两个人在行走的过程中只能在一个点相遇,求除去这个点之外,他们所经过的点的权值的最大值
分析:通过简单分析,我们可以将题目转化为从四个角出发,到相遇节点的各自的最大值相加,各个角到相遇节点的最大值可以通过递推公式来求出,而题目中又要求必须仅有一个点相遇,那也就是说除去这个点之外,其他的点只能允许一个人通过,那么我们可以根据分析可知,两个人经过相遇节点只能有两种途径:
假设相遇节点为(i,j)
- 1、从(1,1)点出发的人由(i-1,j)到达(i,j),并且只能从(i+1,j)走出,从(n,1)点出发的人由(i,j-1)到达(i,j),并只能从(i,j+1)走出去
- 2、从(1,1)点出发的人由(i,j-1)到达(i,j),并且只能从(i,j+1)走出,从(n,1)点出发的人由(i+1,j)到达(i,j),并只能从(i-1,j)走出去
除去上述两种方法之外,可能还有同学认为两人可以分别从(i+1,j),(i-1,j)进入(i,j),如果这样的化,那么他们的下一步一定会经过另一个人走过的路,而这个与题目的要求不符合
通过上述的分析,我们可以得到下面的表达式:
res = max(res,dp1[i-1][j]+dp2[i+1][j]+dp3[i][j-1]+dp4[i][j+1]); 对应的上面的第一种情况
res = max(res,dp1[i][j-1]+dp2[i][j+1]+dp3[i+1][j]+dp4[i-1][j]); 对应的上面的第二种情况
上述表达式中的dp[i][j]表示的是从相应的角出发到(i,j)节点的最大值
还有一点必须要注意:相遇的节点肯定不是边缘上的点,因为在边缘相遇,下一步肯定会重合
AC代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1005;
int n,m;
int dp1[MAXN][MAXN],dp2[MAXN][MAXN],dp3[MAXN][MAXN],dp4[MAXN][MAXN];
int arr[MAXN][MAXN];
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&arr[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
dp1[i][j] = max(dp1[i-1][j],dp1[i][j-1]) + arr[i][j];
for(int i=n;i>=1;--i)
for(int j=m;j>=1;--j)
dp2[i][j] = max(dp2[i][j+1],dp2[i+1][j]) + arr[i][j];
for(int i=n;i>=1;--i)
for(int j=1;j<=m;++j)
dp3[i][j] = max(dp3[i][j-1],dp3[i+1][j]) + arr[i][j];
for(int i=1;i<=n;++i)
for(int j=m;j>=1;--j)
dp4[i][j] = max(dp4[i-1][j],dp4[i][j+1]) + arr[i][j];
int res = 0;
for(int i=2;i<n;++i)
for(int j=2;j<m;++j)
{
res = max(res,dp1[i-1][j]+dp2[i+1][j]+dp3[i][j-1]+dp4[i][j+1]);
res = max(res,dp1[i][j-1]+dp2[i][j+1]+dp3[i+1][j]+dp4[i-1][j]);
}
printf("%d\n",res);
}
return 0;
}