【LeetCode 174】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.

题意:给出一个M*N的迷宫,玩家从左上角K开始寻找路径走到右下角P,只能向右或向下走。
玩家有个初始血量,经过一格时血量会与格子中的数字相加(负数也就意味着血量减少)。在游戏
的任意时刻,只要玩家血量小于或等于0则失败。求玩家要想成功走到右下角所需要的最少初始
血量。

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.

思路:根据题目类型,应该马上想到动态规划。类似的题目有很多,比如寻找从左上角到右下角的最小代价路径、路径总数量等,但本题与这些题有略微的不同。在计算最小代价路径时,从左上到右下计算dp矩阵即可。但本题得从右下逆向往左上计算。

假如从左上往右下dp,每一格 dp[i][j]=min(dp[i-1][j],dp[i][j-1]) 代表到达这一格的最少血量消耗,但这样只能计算出最后到达右下角的最小血量消耗,忽略了一个条件:到任何一格时玩家的血量都必须是正数才行。如果本题改成血量可以降到0及0以下,求到达右下角的最多剩余血量,那么就是传统的最小代价路径求解问题。但血量为正的条件使得这个最小代价路径的途中玩家可能会因血量太低而死亡。

所以改成从右下往左上dp,每一格 dp[i][j] 代表踏入这一格需要的最少血量。在走完最后一个房间的时候血量至少要剩下1,因此最后的状态可以当成是初始状态,由后往前依次决定在每一个位置至少要有多少血量, 这样一个位置的状态是由其下面一个和和左边一个的较小状态决定的。

int calculateMinimumHP(vector<vector<int>>& dungeon) {
	int ROW = dungeon.size(), COL = dungeon[0].size();
	//多一列只是为了放初始值1
	vector<vector<int>> dp(ROW, vector<int>(COL + 1));
	dp[ROW - 1][COL] = 1;
	//初始化最下行
	for (int c = COL - 1; c >= 0; c--) {
		dp[ROW - 1][c] = max(dp[ROW - 1][c + 1] - dungeon[ROW - 1][c], 1);
	}
	//初始化最右列
	for (int r = ROW - 2; r >= 0; r--) {
		dp[r][COL - 1] = max(dp[r + 1][COL - 1] - dungeon[r][COL - 1], 1);
	}
	//dp递推式
	for (int r = ROW - 2; r >= 0; r--) {
		for (int c = COL - 2; c >= 0; c--) {
			int curHealth = min(dp[r][c + 1], dp[r + 1][c]);
			dp[r][c] = max(curHealth - dungeon[r][c], 1);
		}
	}
	return dp[0][0];
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值