- 地下城游戏
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 (P)
思路:
这题一看就是典型的动态规划问题,关键的难点是找到状态转移方程。
由于房间的数字有负有正,从前往后推导,比较难,需要更多的信息。
考虑从后往前,dp[i][j]表示(i,j)到公主房间所需的最小健康点数。
先考虑最后一个房间,是负数-5, 那就意味着到达该房间的点数必须大于等于5+1,才能存活。
如果房间是正数,就意味这,只要能进入该房间就行。也就是最低点数1。
该房间的最小健康点数=max(1, -dungeon[][] + 1);
这样从一个格子到下一个格子的状态转移方程就出来了:
dp[i][j] = max(1, -dungeon[i][j]+min(dp[i+1][j],dp[i][j+1])) //只能向下或向右走 ,
int calculateMinimumHP(vector<vector<int>>& dungeon) {
//动态规划,dp[i][j] 表示从(i,j)格子到终点,所需的最小健康点数
int m = dungeon.size();
int n = dungeon[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
//从后往前
if(dungeon[m-1][n-1] < 0)
{
dp[m-1][n-1] = -dungeon[m-1][n-1] +1; //健康点数始终要大于1
}
else
{
dp[m-1][n-1] = 1; //因为如果大于0 , 只需1,最低即可
}
//最后一列
for(int i = m-2; i >=0; i--)
{
dp[i][n-1] = max(1, -dungeon[i][n-1] + dp[i+1][n-1]); //(i,n-1) 的点数 - 房间点数 = 进入下一个房间的点数
}
//最后一行
for(int i = n-2; i>=0; i--)
{
dp[m-1][i] = max(1, -dungeon[m-1][i] + dp[m-1][i+1]);
}
for(int i = m-2; i >=0; i--)
{
for(int j = n-2; j >=0; j--)
{
dp[i][j] =max(1, -dungeon[i][j] + min(dp[i+1][j], dp[i][j+1])); //选择下方或右方小的
}
}
return dp[0][0];
}