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

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

题目链接

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 ,所以仍然保持不变。

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

正确解法

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

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

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

严格证明


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

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

等价于:

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

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

同样我们可以得到:

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

代码

c++

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int n = 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 (int i = n-1; i >= 0; --i) {
            for (int j = m-1; j >= 0; --j) {
                int minn = min(dp[i+1][j], dp[i][j+1]);
                dp[i][j] = max(1, minn-dungeon[i][j]);
            }
        }
        return dp[0][0];
    }
};
相关文章
|
15天前
|
数据采集 分布式计算 并行计算
mRMR算法实现特征选择-MATLAB
mRMR算法实现特征选择-MATLAB
75 2
|
28天前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
146 3
|
5天前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
|
1月前
|
存储 编解码 算法
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
|
5天前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
|
5天前
|
机器学习/深度学习 算法 自动驾驶
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
|
22天前
|
机器学习/深度学习 算法 数据可视化
基于MVO多元宇宙优化的DBSCAN聚类算法matlab仿真
本程序基于MATLAB实现MVO优化的DBSCAN聚类算法,通过多元宇宙优化自动搜索最优参数Eps与MinPts,提升聚类精度。对比传统DBSCAN,MVO-DBSCAN有效克服参数依赖问题,适应复杂数据分布,增强鲁棒性,适用于非均匀密度数据集的高效聚类分析。
|
22天前
|
开发框架 算法 .NET
基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA
简介:本文介绍基于ADMM的MIMO信号检测算法,结合无穷范数优化与交替方向乘子法,降低计算复杂度并提升检测性能。涵盖MATLAB 2024b实现效果图、核心代码及详细注释,并对比ML、MMSE、ZF、OCD_MMSE与LAMA等算法。重点分析LAMA基于消息传递的低复杂度优势,适用于大规模MIMO系统,为通信系统检测提供理论支持与实践方案。(238字)
|
1月前
|
机器学习/深度学习 传感器 算法
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
【高创新】基于优化的自适应差分导纳算法的改进最大功率点跟踪研究(Matlab代码实现)
155 14
|
5天前
|
机器学习/深度学习 数据采集 负载均衡
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)

热门文章

最新文章