10913 - Walking on a Grid

哈哈,又一道动归。

这道题,状态可以设成两个:一个是从左上方得到的最大值,另一个是从右上方得到的最大值,状态转移也分开求。

f(l, i, j, k)表示状态,其中f(0, i, j, k)表示当前(i, j)点从左上方得到的经过k个负数格子的最大值,状态转移方程为:

f(0, i, j, k,) = max(f(0, i - 1, j, k + t), f(1, i - 1, j, k + t), f(0, i, j - 1, k + t)) + grid[i][j],若当前格子的值为正,t=0,否则为-1;同理可以写出f(1, i, j, k)的状态转移方程。

我写的时候怕格子里的数据太大,用了LL,先把每个格子初始化为负无穷大。若为负无穷大,则值还没求,若为负无穷大+1,则无解。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long
const LL INF = (LL)1 << 60;
int n, K;

LL f[2][80][80][10], grid[80][80];
int mod(int x)
{
    return (x + 2) % 2;
}

LL dp(int i, int j, int k, int l)
{
    if(i < 1 || j < 1 || k < 0) {
        //printf("*%d %d %d %d %lld\n", i, j, k, l, -INF + 1);
        return -INF + 1;
    }
    LL &ans = f[l][i][j][k];
    if(ans != -INF) return ans;
    int t = 0;
    ans = -INF + 1;
    if(grid[i][j] < 0) t = -1;
    if(i > 0)
        ans = max(dp(i - 1, j, k + t, l), dp(i - 1, j, k + t, mod(l - 1)));
    if(l == 0){
        if(j > 1) ans = max(ans, dp(i, j - 1, k + t, l));
    }else{
        if(j < n) ans = max(ans, dp(i, j + 1, k + t, l));
    }
    if(ans != -INF + 1){
        ans += grid[i][j];
    }
    //printf("%d %d %d %d %lld\n", i, j, k, l, f[l][i][j][k]);
    return ans;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    int con = 1;
    while(scanf("%d %d", &n, &K) == 2){
        if(!n && !K) break;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                scanf("%lld", &grid[i][j]);

        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                for(int k = 0; k <= K; k++)
                    f[0][i][j][k] = f[1][i][j][k] = -INF;

        if(grid[1][1] >= 0)
            f[0][1][1][0] = f[1][1][1][0] = grid[1][1];
        else if(K >= 1)
            f[0][1][1][1] = f[1][1][1][1] = grid[1][1];

        LL ans = -INF;
        for(int i = 0; i <= K; i++){
            ans = max(ans, dp(n, n, i, 0));
        }
        if(ans != -INF + 1){
            printf("Case %d: %lld\n", con++, ans);
        }else printf("Case %d: impossible\n", con++);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值