原题地址:
https://oj.leetcode.com/problems/dungeon-game/
题目内容:
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) |
Notes:
-
- 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.
方法:
唉,leetcode也越来越水了。这题是比较单纯的DP题,标Medium还行,标Hard有点让人失望。
步入正题。
定义状态dp[i][j]为,进入i,j坐标【前】,至少需要多少HP,才能从i,j坐标到达终点。
由于在一个坐标时,不是走右就是走下,所以:
设next = min(dp[i + 1][j] , dp[i][j + 1]) , pos = dungeon[i][j]
dp[i][j] = pos >= next ? 1 : next - pos
简单讲一下。首先next的值,是在i,j坐标上的right、down两个选择中,能够以最少HP到达终点的坐标的所需的最少HP值。(有点拗口。。比如说往右走需要进入右边以前有10点HP才能最终到达终点,而往下走则需要5点,那么next的值就是5)
其次,如果i,j坐标能够提供足够的HP保证走到next,那么进入i,j坐标前有1点HP就足够了,保证不死就行;反之,需要用next - pos来算出进入i,j坐标前需要的HP点数。
具体实现上,用一个一维dp数组就可以模拟整个过程了,不需要真的申请一个二维数组。具体可以参考代码,如果不能理解可以留言,我再详细讲讲。
具体代码:
class Solution {
public:
int calculateMinimumHP(vector<vector<int> > &dungeon) {
int ylength = dungeon.size(); // how many sub-array
if (ylength == 0)
return 0;
int xlength = dungeon[0].size(); // how many elements that sub-array contains
if (xlength == 0)
return 0;
int max = ~(1 << 31);
vector<int> res;
for (int i = 0; i < xlength; i ++) {
res.push_back(0);
}
for (int i = ylength - 1; i >= 0; i --) {
for (int j = xlength - 1; j >= 0; j --) {
int x = j + 1;
int y = i + 1;
int right = x < xlength ? res[x] : max;
int down = y < ylength ? res[j] : max;
if (right == max && down == max) {
res[j] = dungeon[ylength - 1][xlength - 1] >= 0 ? 1 : 1 - dungeon[ylength - 1][xlength - 1]; // final point
} else {
int tmp = right > down ? down : right;
int pos = dungeon[i][j];
if (pos >= tmp) {
res[j] = 1;
} else {
res[j] = tmp - pos;
}
}
}
}
return res[0];
}
};