174. 地下城游戏
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。 有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。 为了尽快到达公主,骑士决定每次只向右或向下移动一步。 编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。 例如,考虑到如下布局的地下城,如果骑士遵循最佳路径
右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3 -5 -10 1 10 30 -5 (P) 说明:
- 骑士的健康点数没有上限。
- 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
解题思路 | 反向dp
参考【官方题解】
反向动态规划,即反向 dp
1.状态定义 表示从坐标
到终点所需的最小初始值。
从终点 开始倒推到起点计算每个坐标点的 dp 值
2.动态转移方程:
3.初始条件**:
1.令
2.令
举个栗子**


**
如下图根据题目给的示例计算的dp值,圆圈里的数代表了此位置的dp值。
初始时除了 和
等于 1 外,其他都为
计算顺序是从位置开始计算dp值。如:
然后从计算到
,
到
,
到

代码实现
/*1.骑士的健康点数初始值必须 >= 11.骑士的健康点数任意时刻必须 >= 1*/class Solution {public:int calculateMinimumHP(vector<vector<int>>& dungeon) {int n = dungeon.size();int m = n>0 ? dungeon[0].size():0;//初始条件vector<vector<int>> dp(n+1,vector<int>(m+1,INT_MAX));dp[n][m-1] = 1;dp[n-1][m] = 1;/*dp[i][j] 表示从坐标 (i,j)到终点所需的最小初始值。反向dp,从终点开始计算,计算每个坐标点到终点所需的的最小初始值*/for(int i=n-1;i >= 0;i--) {for( int j = m-1; j >=0; j--) {int tmin = min(dp[i+1][j],dp[i][j+1]);dp[i][j] = max(tmin - dungeon[i][j],1);}}return dp[0][0];}};
