【每日算法Day 65】你能顺利救出地下城里的公主吗?

简介: LeetCode 174. 地下城游戏[1]

题目链接


LeetCode 174. 地下城游戏[1]

题目描述


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

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

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

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

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

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

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

提示:

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

题解


错误解法


首先我们肯定想到的是从左上到右下动态规划,那么对于  这个格子来说,它有两个选择,可以从  或者  过来。

我们令  表示从左上角走到  这个格子所需要的最小生命值,那么我们选择  ,也就是两个来向中较小的那个走过来。但是考虑了当前格子的数值之后,路线上所需生命的最小值是可能增大的,而这时候可能选择两个来向中较大的那个反而更好(因为那个来向数值之和比较大),所以这里就产生了矛盾,无法求解。

举个简单的例子:

1(K) -3 3
0 -2 0
-3 -3 -3(P)

这个例子中如果只看走到格子  的结果的话,肯定是 下 -> 右 -> 右 最好,因为这样初始生命只需要 2 就够了。而另一条路 右 -> 右 -> 下 则需要初始生命 3 。

但是如果继续走到格子  ,那么最优方向一定是从  过来(另一个方向负数太多)。但是到  的最优路线保存的是 下 -> 右 -> 右 这一条,走到终点总和是 -4 ,初始所需最小生命增大为 5 。而另一条原本不怎么好的路线 右 -> 右 -> 下 总和是 -2 ,初始所需最小生命 3 ,所以仍然保持不变。

这样看来原本不好的路线在最后的结果里是可能会变好的,所以不好保存下来直接递推。

正确解法


既然从左上到右下没法动态规划,我们不妨从右下到左上动态规划看看。

我们令  表示从  这个格子走到右下角所需要的最小生命值,同样我们选择两个去向中的较小值  。然后考虑了格子  之后,  就更新为:

为什么这里选择两个去向中所需初始生命较小的那个就没问题了呢?

严格证明


image.png

考虑上图这种情况,这里我把  抽象为了  ,右边一格抽象为了  ,右下角抽象为了  。然后  走下面这条路所需初始生命值最小,路径上格子记为  ,另一条路径上格子记为  。

因为走路径  所需的初始生命值更小,所以我们有:

等价于:

这时候我们在两边  里面同时加上  ,大小关系是不会变的。

而错误解法中,考虑下图这种情况:image.png

同样我们可以得到:

到这里为止和上面正确解法是一模一样的。但是,加上  之后,和上面正解的区别就是,正解求和里每一项都加了,所以大小关系不变,但是错解只有一项加了(就是所有值全加起来),大小关系无法确定

代码


c++

classSolution {
public:  
intcalculateMinimumHP(vector<vector<int>>&dungeon) {  
intn=dungeon.size(), m=dungeon[0].size();  
vector<vector<int>>dp(n+1, vector<int>(m+1, INT_MAX));  
dp[n][m-1] =dp[n-1][m] =1;   
for (inti=n-1; i>=0; --i) {  
for (intj=m-1; j>=0; --j) { 
intminn=min(dp[i+1][j], dp[i][j+1]); 
dp[i][j] =max(1, minn-dungeon[i][j]);  
            }     
        }     
returndp[0][0];  
    }
};

参考资料

[1]

LeetCode 174. 地下城游戏: https://leetcode-cn.com/problems/dungeon-game/

image.png

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~


相关文章
|
3天前
|
运维 监控 数据安全/隐私保护
绝地反击,不做背锅侠!
那么作为运维人员,如何摆脱以上背黑锅的尴尬局面呢?堡垒机当然是破解此局面的绝杀大招。
32 0
|
10月前
|
Cloud Native
【刷题日记】417. 太平洋大西洋水流问题
本次刷题日记的第 45 篇,力扣题为:417. 太平洋大西洋水流问题 ,中等
|
10月前
|
C语言
【蓝桥杯刷题】盗版Huybery系列之手抓饼赛马
【蓝桥杯刷题】盗版Huybery系列之手抓饼赛马
79 0
|
3天前
|
消息中间件 缓存 NoSQL
记一次蚂蚁金服四面遭虐,面试水太深,过河的渡船你造好了吗?
有道无术,术可成;有术无道,止于道;以术识道,以道御术
|
11月前
【每日一道智力题】之 赛马找最快
【每日一道智力题】之 赛马找最快
99 0
|
12月前
|
算法 C++
【每日算法Day 65】你能顺利救出地下城里的公主吗?
【每日算法Day 65】你能顺利救出地下城里的公主吗?
|
前端开发 小程序 Java
1024特刊|要不是家里穷,我也不想当码农
三掌柜有一句说的好:要不是家里穷,我也不想当码农;要不是家里没矿,我也不想四处流浪。
628 1
1024特刊|要不是家里穷,我也不想当码农
|
传感器 监控 小程序
A计划救公主
可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。
155 0
爬梯子&&卖卖股份的最佳时期(跑路人笔记)
爬梯子&&卖卖股份的最佳时期(跑路人笔记)
爬梯子&&卖卖股份的最佳时期(跑路人笔记)