前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【每日算法Day 65】你能顺利救出地下城里的公主吗?

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

作者头像
godweiyang
发布2020-03-24 11:09:14
5050
发布2020-03-24 11:09:14
举报
文章被收录于专栏:算法码上来

题目链接

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++

代码语言:javascript
复制
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];
    }
};

参考资料

[1]

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法码上来 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目链接
  • 题目描述
  • 题解
    • 错误解法
      • 正确解法
        • 严格证明
        • 代码
          • c++
            • 参考资料
            相关产品与服务
            NLP 服务
            NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档