龙与地下城游戏问题

思路来源:讨论区第一条评论

这题使用动态规划的方法来解。我们以示例为例来解释。
1.假设矩阵只有一个值,也就是右下角的-5,那么骑士需要6点血。
2.对于最下面一行来说,只能往右走,所以可以求出进入每一格需要的血量。在30这里,设需要的血量为x,进入下一格需要6点血,那么应该有x + 30 >=6, x >= -24, 算出来x小于0,说明这个格子是加血的,并且加的血足够,x = 1就可以了。那么最下面一行依次就是,{1,1,6}。同理最右边一列是{2,5,6}。
3.接下看递推公式,用hpMatrix表示骑士从任意一格到达终点所需要的最少血量,matrix表示输入矩阵。对于任意一格matrix[i][j]来说,骑士进入它并且能够成功到达终点所需要的血量,应该是进入这个格子本身消耗的血量,加上向右和向下其中需要较少的血量。也就是hpMatirix[i][j] = -matrix[i][j] + min(hpMatirx[i][j + 1], hpMatrix[i + 1][j])。 以-10这一格为例,进入它会消耗10滴血,它右边的格子需要5滴血,下边的格子需要1滴血,所以向下走,因此进入这一格骑士需要11滴血。

在这里插入图片描述

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        int rows=dungeon.length;
        int coloums=dungeon[0].length;
        int[][] dp=new int[rows][coloums];

        //初始化右下角的格子:
        //如果在dungeon里右下角的数大于0,就是证明是加血的,那么进入到这个格子的最少血量只需要1;
        //如果在dungeon里右下角的数小于0的话就说明这个格子是扣血的,用1减去这个负数,那么就能保证进入到这个格子至少还剩余1血
        dp[rows-1][coloums-1]=dungeon[rows-1][coloums-1]>0? 1 : 1 - dungeon[rows-1][coloums-1];

        //初始化最后一行,最后一行只能往右走
        for(int j = coloums-2;j>=0;j--){
            //要判断当前格子是加血的还是扣血的
            if(dp[rows-1][j+1] - dungeon[rows-1][j]<=0)//1-30小于0,即说明当前格子是加血的
                dp[rows-1][j] = 1;//所有到达这个格子时最小的生命值可以为1
            else//如果大于0的话就说明当前格子是负数,进入当前格子至少比这个负数大1
                dp[rows-1][j] = dp[rows - 1][j + 1] - dungeon[rows - 1][j];
        }

        //初始化最后一列,最后一列只能往下走
        for(int i = rows-2;i>=0;i--){
            if(dp[i+1][coloums-1] - dungeon[i][coloums-1] <=0)//说明是加血的
                dp[i][coloums-1]=1;//进入当前格子生命最少是1就行
            else
                dp[i][coloums-1]=dp[i + 1][coloums-1] - dungeon[i][coloums-1];
        }

        // 从后往前处理剩余位置,取最小值
        for (int i = rows - 2; i >= 0; --i) {
            for (int j = coloums - 2; j >= 0; --j) {
                //往右走需要多少血
                int toLeft = dp[i][j + 1] - dungeon[i][j] > 0 ? dp[i][j + 1] - dungeon[i][j] : 1;
                //往上走需要多少血
                int toDown = dp[i + 1][j] - dungeon[i][j] > 0 ? dp[i + 1][j] - dungeon[i][j] : 1;

                dp[i][j] = toLeft > toDown ? toDown : toLeft;
            }
        }
        return dp[0][0];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值