题意:一个人从左上走到右下,一个人从左下走到右上,两个人必须有一个点作为见面点,见面点的权值不能拿,问按照规则走,取得最大权值的和为多少
只是考虑左上角那个点的话起点记作start,假设在(i,j)点处相遇,这个点记作now,然后继续走到终点右下角记作end,那么是不是这条路线的和就应该是start->now + now -> end这两段的数值的和,当然了不加now那个点;
那我们再想,start->now这个点我们已经用dp求出来了,其实now->end的总数值是不是就等于end->now的总数值,因此我们可以转化为求end->now的最大值,那么这个问题也就转化成了矩阵的四个角分别求dp,然后枚举每个点为相遇点,比较得出最大的即可
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 1e3+10;
int mp[Max][Max];
int dp1[Max][Max],dp2[Max][Max],dp3[Max][Max],dp4[Max][Max];
int n,m;
int main(){
int i,j;
cin >> n >> m;
memset(mp,0,sizeof(mp));
for(i = 1; i <= n; i++){
for(j = 1; j <= m; j++){
cin >> mp[i][j];
}
}
//左上角求dp1
memset(dp1,0,sizeof(dp1));
for(i = 1; i <= n; i++){
for(j = 1; j <= m; j++){
dp1[i][j] = max(dp1[i-1][j],dp1[i][j-1]) + mp[i][j];
}
}
//左下角求dp2
memset(dp2,0,sizeof(dp2));
for(i = n; i >= 1; i--){
for(j = 1; j <= m; j++){
dp2[i][j] = max(dp2[i+1][j],dp2[i][j-1]) + mp[i][j];
}
}
//右上角求dp3
memset(dp3,0,sizeof(dp3));
for(i = 1; i <= n; i++){
for(j = m; j >= 1; j--){
dp3[i][j] = max(dp3[i-1][j],dp3[i][j+1]) + mp[i][j];
}
}
//右下角求dp4
memset(dp4,0,sizeof(dp4));
for(i = n; i >= 1; i--){
for(j = m; j >= 1; j--){
dp4[i][j] = max(dp4[i+1][j],dp4[i][j+1]) + mp[i][j];
}
}
//枚举每个相遇点求出总和,并比较选出最大值
int Max = -1;
for(i = 2; i < n; i++){
for(j = 2; j < m; j++){
Max = max(Max,dp1[i-1][j]+dp2[i][j-1]+dp3[i][j+1]+dp4[i+1][j]);
Max = max(Max,dp1[i][j-1]+dp2[i+1][j]+dp3[i-1][j]+dp4[i][j+1]);
}
}
cout << Max << endl;
return 0;
}