链接
[思路]:
首先这个题目就是问从左上角传到右下角,再从左下角传回右上角的路径和的最大值,每个位置不能重复走
其实考虑后可以发现,可以将问题简化成从左上角到右下角的两条路径和,那么不能重复走怎么处理呢?
经过思考我们可以知道显然不会从相同的格子转移获得最大值的情况,所以问题又可以简化为从左上角走
到右下角的两条路径和(每个位置只能取一次的值)
所以容易得到状态{x1, y1, x2, y2}代表第一条路径走到(x1, y1),第二条路径走到(x2, y2)
该状态是个O(n^4)的转移
其实可以发现将x1 + y1 = x2 + y2 = k 然后就可以将维度变化为(k, x1, x2)
就可以得到对应的n^3的状态
所以对应的状态转移方程为
dp[k][i][j] = max(dp[k - 1][i - 1][j - 1] + score(k, i, j), dp[k][i][j]);
//右下
dp[k][i][j] = max(dp[k - 1][i][j - 1] + score(k, i, j), dp[k][i][j]);
//下右
dp[k][i][j] = max(dp[k - 1][i - 1][j] + score(k, i, j), dp[k][i][j]);
//右右
dp[k][i][j] = max(dp[k - 1][i][j] + score(k, i, j), dp[k][i][j]);
score为判断是否在一个格子,如果在一个格子只加一次的值
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 55;
int arr[MAXN][MAXN], dp[200][MAXN][MAXN];
int score(int k, int i, int j){
if(i == j && k - i == k - j){
return arr[i][k - i];
}
return arr[i][k - i] + arr[j][k - j];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cin >> arr[i][j];
}
}
for(int k = 2; k <= n + m; k ++){
for(int i = 1; i <= min(n, k); i ++){
for(int j = 1; j <= min(n, k); j ++){
//下下
dp[k][i][j] = max(dp[k - 1][i - 1][j - 1] + score(k, i, j), dp[k][i][j]);
//右下
dp[k][i][j] = max(dp[k - 1][i][j - 1] + score(k, i, j), dp[k][i][j]);
//下右
dp[k][i][j] = max(dp[k - 1][i - 1][j] + score(k, i, j), dp[k][i][j]);
//右右
dp[k][i][j] = max(dp[k - 1][i][j] + score(k, i, j), dp[k][i][j]);
}
}
}
cout << dp[n + m][n][n] << endl;
return 0;
}