欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LeetCode174. 地下城游戏

程序员文章站 2022-07-12 08:54:29
...

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

-2 (K) -3 3
-5 -10 1
10 30 -5 §

说明:

骑士的健康点数没有上限。

任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

反向DP,假设骑士找到公主时剩余生命值为1时,倒推进入时需要的最小生命值

	// 地下城游戏,思路是倒着计算,假设找到公主时,骑士的生命值剩余为1点时,进入时最少需要多少生命值
	int calculateMinimumHP(vector<vector<int>>& dungeon) {
		if (dungeon.size() == 0)
			return 0;
		int surplus = 1; // 找到公主时,最少剩余1点健康点数
		int column = dungeon[0].size(); // 列数
		int rownum = dungeon.size();//行数
		if (column == 1) // 单列
		{
			vector<int> vecCache(vector<int>(rownum, -1));
			vecCache[rownum - 1] = max(surplus, surplus - dungeon[rownum - 1][0]);
			for (int i = rownum - 2; i >= 0; i--)
			{
				vecCache[i] = max(1, vecCache[i + 1] - dungeon[i][0]);
			}
			return vecCache[0];
		}
		if (rownum == 1) // 单行
		{
			vector<int>vecCache(vector<int>(column, -1));
			vector<int> vec = dungeon[0];
			vecCache[column - 1] = max(surplus, surplus - vec[column - 1]);
			for (int i = column - 2; i >= 0; i--)
			{
				vecCache[i] = max(1, vecCache[i + 1] - vec[i]);
			}
			return vecCache[0];
		}
		vector<vector<int>> vecCache(rownum, vector<int>(column, -1)); // 缓存到每个点所需的最小生命值
		vecCache[rownum - 1][column - 1] = max(surplus, surplus - dungeon[rownum - 1][column - 1]);
		findMinimumHP(rownum - 2, column - 1, dungeon, vecCache);
		findMinimumHP(rownum - 1, column - 2, dungeon, vecCache);
		return vecCache[0][0];
	}

	void findMinimumHP(int startY, int startX, vector<vector<int>>& dungeon, vector<vector<int>>&vecCache) // startY开始的行数,startX开始的列数
	{
		if (vecCache[startY][startX] != -1)
			return;
		int column = dungeon[0].size();
		if (startY == dungeon.size() - 1) // 该点位于下边界,则该点所需最小值由它右边的结点推算出来
		{
			vecCache[startY][startX] = max(1, vecCache[startY][startX + 1] - dungeon[startY][startX]);
		}
		else if (startX == column - 1) // 该点位于左边界,则该点所需最小值由它下边的结点推算出来
		{
			vecCache[startY][startX] = max(1, vecCache[startY + 1][startX] - dungeon[startY][startX]);
		}
		else if(vecCache[startY + 1][startX] != -1 && vecCache[startY][startX + 1] != -1)
		{
			vecCache[startY][startX] = max(1, min(vecCache[startY + 1][startX] - dungeon[startY][startX], vecCache[startY][startX + 1] - dungeon[startY][startX]));
		}
		if (vecCache[startY][startX] != -1)
		{
			if (startY - 1 >= 0)
			{
				findMinimumHP(startY - 1, startX, dungeon, vecCache);
			}
			if (startX - 1 >= 0)
			{
				findMinimumHP(startY, startX - 1, dungeon, vecCache);
			}
		}
	}