leetcode 174. Dungeon Game

博客围绕骑士从左上角出发,在二维网格状的地牢中解救右下角公主的问题展开。骑士在不同房间会增减血量,血量为 0 则死亡。通过动态规划思路,定义 dp 数组,倒推计算从各位置出发所需的最小血量,最终得出从左上角出发的最小初始血量。

The demons had captured the princess § and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0’s) or contain magic orbs that increase the knight’s health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight’s minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

Note:

The knight’s health has no upper bound.
Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

在这里插入图片描述

骑士从左上角的(K)出发,(Knight: 骑士),走到正数的格子是加那么多数值的血量,负数的格子是掉血,问从左上角出发走到右下角解救公主(P:Princess)的位置,刚开始左上角的位置至少需要多少血量。
注意在任意一格如果血量降为0,就挂掉了,不能再继续往前走,所以每一格的血量最少是1

思路:
首先看最后P的位置,到达这个位置减掉这个格子的血量之后,至少要剩余1的血量
x - 5 = 1 -> x = 6, 所以要带着6的血量进入P的格子,才不会挂掉

倒推:现在从P上面一格出发,进入这一格会+1, 要保证在这一格保留6的血量才能进入P,所以x+1 = 6 -> x = 5

所以定义一个dp数组,假设dp[i][j]表示从[i][j]出发需要的血量,那么
向右走时: dp[i][j] + dungeon[i][j] = dp[i][j+1]
向下走时: dp[i][j] + dungeon[i][j] = dp[i+1][j]
而只需要在这两种路径中取较小的
所以:
dp[i][j] = min(dp[i][j+1], dp[i+1][j]) -dungeon[i][j]
另外还要保证dp[i][j]至少是1

边界情况只需要考虑一个方向就行了

所以可以得到以下数组:

752
6115
116

最后返回dp[0][0]就行了,就是从[0][0]出发时的血量

    public int calculateMinimumHP(int[][] dungeon) {
        if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {
            return 0;
        }
        
        int height = dungeon.length;
        int width = dungeon[0].length;
        
        int[][] dp = new int[height][width];
        
        //P position..
        dp[height - 1][width - 1] = Math.max(1, 1 - dungeon[height - 1][width - 1]);
        
        //right border..
        for (int i = height - 2; i >= 0; i--) {
            dp[i][width - 1] = Math.max(1, dp[i + 1][width - 1] - dungeon[i][width - 1]);
        }
        
        //down border..
        for (int j = width - 2; j >= 0; j--) {
            dp[height - 1][j] = Math.max(1, dp[height - 1][j + 1] - dungeon[height - 1][j]);
        }
        
        //other grids..
        for (int i = height - 2; i >= 0; i--) {
            for (int j = width - 2; j >= 0; j--) {
                dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
                dp[i][j] = Math.max(1, dp[i][j]);
            }
        }
        
        return dp[0][0];
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值