一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
由于题目要求在出生点也要扣除对应的血量,所以我们把移动的过程看成:刚刚移动到本地未扣除血量 -》扣除血量 -》试图移动到下一位置 这样三个过程:
因为 原hp + 原dungeon = 现hp
所以 原hp = 现hp - 原dungeon
因为路径只有向下或向右两条路可走,所以原有hp可以往右走,或者往下走,目标是原hp所需最少,所以取min
即 hp[i][j] = hp[i+1][j] - dungeon[i][j] 或 hp[i][j] = hp[i][j+1] -dungeon[i][j],因为是保证minimum,所以应取二者最小者, 即 hp[i][j] = Math.min(hp[i+1][j],hp[i][j+1]) - dungeon[i][j]
如果计算后存在负值,则直接设为1,因为最小血量不能低于1
为了方便处理,把方格扩大1,且将扩大的位置中挨着终点位置初始化为1,因为最少需要1血,其余初始化为最大值, 从终点开始算起。
class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int m = dungeon.length;
int n = dungeon[0].length;
int[][] dp = new int[m+1][n+1];
for (int i = 0; i <= n; i++)
dp[m][i] = Integer.MAX_VALUE;
for (int i = 0; i <= m; i++)
dp[i][n] = Integer.MAX_VALUE;
dp[m-1][n] = 1;
dp[m][n-1] = 1;
for (int i = m-1; i >= 0; i--) {
for (int j = n-1; j >= 0; j--) {
dp[i][j] = Math.max(1, Math.min(dp[i+1][j], dp[i][j+1])-dungeon[i][j]);
}
}
return dp[0][0];
}
}