CF dp 递推
题意:
给出nxm个数字矩阵,求出从左上角到右下角的最大权值和,权值就是数字,求出从左下到右上的最大权值和,当然两条路只能交叉一个位置,并且此位置上的权值不能算入和。求出两条路的最大权值和。
思路:
- 注意边界不能作为交叉位置。
终极思想是枚举相叉位置,知道位置之后只需求出每一条路是怎么走的就行,很容易得出只有两种走法,别想太多,试试就知道。那么四种走法dp求出既可。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn][4];
int a[maxn][maxn];
int main()
{
// freopen("in.txt","r",stdin);
int n,m;
scanf("%d%d",&n,&m);
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++) {
for(int j = 1;j <= m; j++) {
dp[i][j][0] = a[i][j] + max(dp[i][j-1][0],dp[i-1][j][0]);
}
}
for(int i = n;i >= 1; i--) {
for(int j = m;j >= 1; j--) {
dp[i][j][1] = a[i][j] + max(dp[i+1][j][1],dp[i][j+1][1]);
}
}
for(int i = n;i >= 1; i--) {
for(int j = 1;j <= m; j++) {
dp[i][j][2] = a[i][j] + max(dp[i+1][j][2],dp[i][j-1][2]);
}
}
for(int i = 1;i <= n; i++) {
for(int j = m;j >= 1; j--) {
dp[i][j][3] = a[i][j] + max(dp[i-1][j][3],dp[i][j+1][3]);
}
}
int ans = 0;
for(int i = 2;i < n; i++) {
for(int j = 2;j < m; j++) {
ans = max(ans,dp[i-1][j][0]+dp[i+1][j][1]+dp[i][j-1][2]+dp[i][j+1][3]);
ans = max(ans,dp[i][j-1][0]+dp[i][j+1][1]+dp[i+1][j][2]+dp[i-1][j][3]);
}
}
printf("%d\n",ans);
return 0;
}