题目大意:给你一个n * m的矩阵,矩阵上面有对应的数字,起始位置是(1,1)
现在要求你从起始位置走到终点(n,m),只能往右或者往下走,接着从终点走回起始位置,只能往上或者往左走,每个格子只能被走一次,问能得到的数字的最大和是多少
解题思路:从终点往回走,就相当于从起点往终点走,所以就当成从起点走两条不相交的路走到终点
因为只能往右或者往下,所以走的步数最多是n + m - 2
接着设dp[step][row1][row2]表示走了step步,第一条线路走到了row1行,第二条线路走到了row2行之后所能得到的最大数值和是多少
接着枚举每条线路的方向,进行记忆化搜索即可
现在的问题是,怎么判断走到同一个位置了,其实很简单,只要判断一下row1是否等于row2即可,因为所走的步数是一样的,减去行之后,就可以得到列的位置了,所以当row1 == row2时,就走到同一个地方了,这种就要剪掉
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 110;
int val[N][N], dp[2 * N][N][N];
int n, m, cas = 1;
int dfs(int step, int row1, int row2) {
if (row1 == row2 && !(row1 == 0 || row1 == n - 1)) return -INF;
if (step == n + m - 2 && row1 == row2 && row1 == n - 1) return val[n - 1][m - 1];
if (~dp[step][row1][row2]) return dp[step][row1][row2];
int ans = -INF;
//都往下走
if (row1 + 1 < n && row2 + 1 < n)
ans = max(ans, dfs(step + 1, row1 + 1, row2 + 1));
//下右
if (row1 + 1 < n && step - row2 + 1 < m)
ans = max(ans, dfs(step + 1, row1 + 1, row2));
//右右
if (step - row1 + 1 < m && step - row2 + 1 < m)
ans = max(ans, dfs(step + 1, row1, row2));
//右下
if (step - row1 + 1 < m && row2 + 1 < n)
ans = max(ans, dfs(step + 1, row1, row2 + 1));
ans += val[row1][step - row1];
if (row1 != row2)
ans += val[row2][step - row2];
return dp[step][row1][row2] = ans;
}
void solve (){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &val[i][j]);
memset(dp, -1, sizeof (dp));
printf("Case %d: %d\n", cas++, dfs(0, 0, 0));
}
int main() {
int test;
scanf("%d", &test);
while (test--) solve();
return 0;
}