GH1995 / leetcode-test-and-run

方便 leetcode 刷题的小工具
GNU General Public License v2.0
0 stars 0 forks source link

174. Dungeon Game 地牢游戏 #40

Open GH1995 opened 5 years ago

GH1995 commented 5 years ago

174. Dungeon Game

Difficulty: Hard

The demons had captured the princess (P) 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.

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

Note:

Solution

Language: C++

class Solution {
 public:
  int calculateMinimumHP(vector<vector<int>>& dungeon) {
    int m = dungeon.size(), n = dungeon.front().size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
    dp[m][n - 1] = 1;
    dp[m - 1][n] = 1;
​
    for (int i = m - 1; i >= 0; --i)
      for (int j = n - 1; j >= 0; --j)
        dp[i][j] = max(1, min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]);
​
    return dp[0][0];
  }
};
GH1995 commented 5 years ago

dp[i][j]

用来表示当前位置 (i, j) 出发的起始血量,最先处理的是公主所在的房间的起始生命值,然后慢慢向第一个房间扩散

逆向推正是本题的精髓所在

进一步来说,应该是由较小的可生存血量决定的,因为较我们需要起始血量尽可能的少

如果公主房间还需要掉血的话,那么掉血后剩1才能保证起始位置的血量最小 由于我们知道到达公主房间后,骑士火拼完的血量至少为1,那么此时公主房间的右边和下边房间里的数字我们就都设置为1

dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j])

我们的二维dp数组比原数组的行数列数均多1个,先都初始化为整型数最大值INT_MAX,由于我们知道到达公主房间后,骑士火拼完的血量至少为1,那么此时公主房间的右边和下边房间里的数字我们就都设置为1,这样到达公主房间的生存血量就是1减去公主房间的数字和1相比较,取较大值