LightOJ - 1071 Baker Vai(记忆化搜索)

题目大意:给你一个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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值