题目:
The demons had captured the princess (P) and im*ed 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:
- 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 im*ed.
分析:
给定一个二维数组,一个骑士从左上角开始,只能向下或者向右走,最终要走到右下角救公主。每经过一个格子,要减去或加上相应的生命值,骑士要活着达到右下角,求骑士初始生命值最低为多少。
我们可以维护一个二维数组用来表示骑士在当前格子也就是dp[ i ][ j ]需要的最少生命值。先来看一个特殊的情况,因为到达最后一个格子,加上dungeon[ m ][ n ]后要有1生命值。如果dungeon[ m ][ n ]是负数,骑士到达该位置时要扣去相应的生命值,且最少要1生命,如果dungeon[ m ][ n ]是正数,则只需要1生命就够了,因为到这个位置还可以加生命值,所以不难发现dp[ m ][ n ] = max(1 - dungeon[ m ][ n ],1)。下面再来看通常情况,dp[ i ][ j ]的值实际上是由dp[ i+1 ][ j ]和dp[ i ][ j+1 ]来决定的,也就是骑士右面和下面哪个需要的生命值越少,则骑士会选择那条较少的路线。所以动态转移方程dp[ i ][ j ] = max(min(dp[ i+1 ][ j ],dp[ i ][ j+1 ]) - dungeon[ m ][ n ],1)。
为了方便计算我们可以扩充一行一列,便于计算边界值。
-2 (K) | -3 | 3 |
-5 | -10 | 1 |
10 | 30 | -5 (P) |
7 | 5 | 2 | INT_MAX |
6 | 11 | 5 | INT_MAX |
1 | 1 | 6 | 1 |
INT_MAX | INT_MAX | 1 | INT_MAX |
程序:
class Solution { public: int calculateMinimumHP(vector<vector<int>>& dungeon) { int m = dungeon.size(); int n = dungeon[0].size(); vector<vector<int>> res(m+1, vector<int>(n+1,INT_MAX)); res[m][n-1] = res[m-1][n] = 1; for(int i = m-1; i >= 0; --i){ for(int j = n-1; j >= 0; --j){ res[i][j] = max(min(res[i+1][j], res[i][j+1])-dungeon[i][j], 1); } } return res[0][0]; } };