Leetcode-174-地下城游戏

题目

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7

-2 (K) -3 3
-5 -10 1
10 30 -5 (P)

说明:

  • 骑士的健康点数没有上限。
  • 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

动态规划

此处需要按照从右下角到左上角的顺序进行动态规划.

假设dp[i][j]为在位置(i, j)到终点所需要的最小起始生命值. 假设dp[i+1][j]dp[i][j+1]是已知的, 那么dp[i][j]应该等于dp[i+1][j]dp[i][j+1]的最小值, 再减去当前位置所要消耗的生命值dungeon(i,j), 并且要注意, 初始生命值应该是大于等于1的.

根据上述描述可知, 动态转移方程为

对于边界条件, 需要对dp[n][m-1]dp[n-1][m]设置为1, 而dp其他位置则需要设置为Integer.MAX_VALUE.

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int n = dungeon.length, m = dungeon[0].length;
int dp[][] = new int[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
dp[n][m - 1] = dp[n - 1][m] = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = m - 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];
}
}

image-20200713103520292