题目链接:
https://leetcode-cn.com/problems/dungeon-game/
难度:困难
174. 地下城游戏
一些恶魔抓住了公主(P)并将她关在了地下城的右下
角。地下城是由 M x N 个房间组成的二维网格。我们英勇
的骑士(K)最初被安置在左上角的房间里,他必须穿过地下
城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数
在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失
去健康点数(若房间里的值为负整数,则表示骑士将损失
健康点数);其他房间要么是空的(房间里的值为 0),要
么包含增加骑士健康点数的魔法球(若房间里的值为正整数,
则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一
步。
编写一个函数来计算确保骑士能够拯救到公主所需的最
低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路
径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为
7。
-2 (K) -3 3
-5 -10 1
10 30 -5 (P)
说明:
骑士的健康点数没有上限。
任何房间都可能对骑士的健康点数造成威胁,也可能增
加骑士的健康点数,包括骑士进入的左上角房间以及公主被
监禁的右下角房间。
不算很难 相对于困难程度的题是有些简单了(虽然不是自己独立做出来的。。。)
有几个需要注意的点:
-
从右下到左上 这道题目一看就是动态规划 毫无疑问。但是从左上到右下计算很麻烦 选择从右下到左上
(从左上到右下需要记录两个值
1 从出发点到当前点的路径和
2 从出发点到当前点所需的最小初始值路径和 最小初始值不一样 比如: -1 4 0 2 -3 3 1 4 -1 从(0,0)->(1,1) 路径和为0 最小初始值为2 (路径和是为了计算下一步所保存的)
dp[i][j] 记录从(i,j)到(m,n)的最小值
不考虑边界情况 方程为:
dp[i][j]=max(min(dp[i+1][j],dp[i][j+1])-dungeon[i][j],1)
考虑边界情况
i=n-1或j=m-1时(不同时成立) 对于min(dp[i+1][j],dp[i][j+1])可以将dp中设置为最大值 这样就会选择未越界的一个
i=n-1且j=m-1 dp[i+1][j] dp[i][j+1]均越界所以 可以设置dp[n-1][m]=dp[n][m-1]=1(当然你也可以只设置一个)
为什么是1 注意:
骑士的初始健康点数为一个正整数。如果他的健康点
数在某一时刻降至 0 或以下,他会立即死亡。
任何房间都可能对骑士的健康点数造成威胁,包括骑士
进入的左上角房间以及公主被监禁的右下角房间。
必须保证勇者在经过公主房间后依然可以剩余1点生命
所以可以设置dp[n-1][m]=dp[n][m-1]=1 这样看保证在经
过(n-1,m-1)后剩余血量为1点
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int n = dungeon.size();
int m = dungeon[0].size();
vector<vector<int>> dp(n + 1, vector<int>(m + 1, INT_MAX));
dp[n-1][m]=dp[n][m-1]=1;
for (int i=n-1;i>=0;i--){
for (int j=m-1;j>=0;j--){
dp[i][j]=max(min(dp[i+1][j],dp[i][j+1])-dungeon[i][j],1);
}
}
return dp[0][0];
}
};