动态规划怎么学?
学习一个算法没有捷径,更何况是学习动态规划,
跟我一起刷动态规划算法题,一起学会动态规划!
1. 题目解析
题目链接:174. 地下城游戏 - 力扣(Leetcode)
勇者从左上角开始,往右或者往下走,遇到正数回血,遇到负数掉血,
求到右下角的时候最低需要多少初始血量?
2. 算法原理
1. 状态表示
1. 第一种思路是以某一个路径为结尾来分析:
所以dp[ i ][ j ] 表示到这个位置,最低需要的初始血量。
但是这个思路不行,因为初始血量不仅会受到前面路径的影响,还会受到后面路径的影响。
2. 第二种思路是从起点发来分析
所以dp[ i ][ j ] 表示从[ i,j ] 出发,到达终点需要的最低血量。
2. 状态转移方程
所以状态转移方程就有两种情况:
1. 往右走一格直到终点:dp[ i ][ j ] + d[ i ][ j ] >= dp[ i ][ j + 1 ]
这个的意思是,dp[ i ][ j ] 到终点的最低健康点数要大于或等于右边一格
2. 往下走一格直到终点:dp[ i ][ j ] + d[ i ][ j ] >= dp[ i + 1 ][ j ]
这个的意思是,dp[ i ][ j ] 到终点的最低健康点数要大于或等于下面一格
而我们要求的是最低的健康点数,所以要求他们的最小值:
dp[ i ][ j ] = min( dp[ i ][ j + 1 ],dp[ i + 1 ][ j ] ) - d[ i ][ j ]
这里要注意一点,有可能出现个很大的血包,导致负血的状态出现,我们可以用:
dp[ i ][ j ] = max( 1,dp[ i ][ j ] ) 如果出现负血,就换成1血。
3. 初始化
为了防止越界,我们需要在最右边和最下面多加一行,
救玩公主之后需要1滴血,所以终点位置的右边初始化个1就行,
因为是选最小值,所以把其他位置都初始化成无穷大即可。
4. 填表顺序
从下往上,从右往左。
5. 返回值
我们需要的是从[ 0,0 ]位置出发的最低血量,所以就返回的是dp[ 0 ][ 0 ]
3. 代码编写
class Solution { public: int calculateMinimumHP(vector<vector<int>>& dungeon) { int m = dungeon.size(), n = dungeon[0].size(); vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX)); dp[m - 1][n] = 1; for(int i = m - 1; i >= 0; i--) { for(int j = n - 1; j >= 0; j--) { dp[i][j] = min(dp[i][j + 1], dp[i + 1][j]) - dungeon[i][j]; dp[i][j] = max(dp[i][j], 1); } } return dp[0][0]; } };
写在最后:
以上就是本篇文章的内容了,感谢你的阅读。
如果感到有所收获的话可以给博主点一个赞哦。
如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~