动态规划之地下城游戏

这篇具有很好参考价值的文章主要介绍了动态规划之地下城游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 题目分析

题目链接选自力扣 : 地下城游戏
image.png
一开始看到这么多文字, 头都大了. 下面就来根据示例的图帮助理解一下
image.png
骑士每次只能向右或者向下走一步, 我们可以倒推一下示例的路线, 很容易就可以知道
image.png

2. 状态表示

按照我们往常的经验, 肯定是以 ( i, j ) 位置为结尾, 表示从起点到 ( i, j ) 位置时的所需的初始最低血量. 现根据这个状态表示我们来推导一下状态转移方程

还是根据最近的一步来进行划分.
image.png
还是一样, 求解到达 ( i, j ) 位置时的最低初始血量需要先求解到达 ( i, j-1 ) 的最低初始血量 dp[i, j-1] 和 到达 ( i-1, j ) 时的最低初始血量.

但是这有一个问题, 到达 ( i, j ) 位置的初始血量不仅仅受到 ( i, j-1 ) 位置和 ( i-1, j ) 位置的影响. 什么意思呢 ? 还是结合示例 1 来讲解 :
image.png
终点的最低血量不仅仅搜到画红圈的 1 和 30 的两个位置的最低血量影响. 还受到画绿色圈的影响. 它是有很多条不同路径的. 进入任何一个房间击败不了恶魔都需要重设起始点的初始血量. 因此此时的状态表示以某个位置结尾时从起始点到达该位置的最低初始血量就无法推导出状态转移方程了. 因为它收到的影响不仅仅是两个方向的.

那么, 这种表示方法行不通, 我们还有一种经验方法, 也就是以 ( i, j ) 位置为起点, 表示从 ( i, j ) 位置开始到达终点时所需要的最低初始血量.

3. 状态转移方程

以 i, j ) 位置为起点, 表示从 ( i, j ) 位置开始到达终点时所需要的最低初始血量. 推导此时的状态转移方程 dp[i][j] : 还是以最近的一步来划分问题
image.png

  1. 从 ( i, j ) 位置出发往 ( i, j+1 ) 位置走

什么时候才能从 ( i, j ) 位置正确进入到 ( i, j + 1 ) 位置呢 ? 假设 ( i, j ) 位置此时最低初始血量为 X, 当 X + dungeon[i][j] >= dp[i][j+1] 时才能有机会到达终点. 题目要求最低初始血量, 取等时即可

dp 表里存的是从某个位置出发时的最低血量. 此时这个位置的最低血量为 X, 想要走出这个位置就需要先击败里面的恶魔 dungeon[i][j], 之后剩余血量 X + dungeon[i][j] 也就是此时进入 ( i, j+1 ) 的最低初始血量必须要大于等于 ( i, j+1 ) 的最低初始血量 dp[i][j+1] 才能进入, 否则无法到达终点.

此时 X = dp[i][j+1] - dungeon[i][j]

  1. 从 ( i, j ) 位置出发往 ( i+1, j ) 位置走

同理, 从 ( i, j ) 位置出发往 ( i+1, j ) 想要到达终点所需要的最低初始血量为 dp[i+1][j] - dungeon[i][j]

由于我们求的是从某点出发到终点的最低初始血量, 最终 dp[i][j] = Math.min(dp[i][j+1], dp[i+1][j] ) - dungeon[i][j]

PS :有一点是需要注意的, 当 dungeon[i][j] 非常大的时候, dp[i][j] 最终是一个小于 0 的数. 这是什么意思 ?

也就是当你进入 ( i, j ) 位置时, 这里面是一个非常大的血包 dungeon[i][j] 此时我进入 ( i, j ) 位置时自身血量哪怕是负数最终也可以进入到 ( i, j+1 ) 位置. 这是不合理的, 负数就应该直接死亡. 必须保证在进入 ( i, j ) 位置时它的血量大于 0 才行.

因此我们需要对最终的 dp[i][j] 进行处理. dp[i][j] = Math.max( 1, dp[i][j] ). 也就是进入某处时的最低初始血量必须是大于 0 才能进入 !

4. 初始化

根据状态转移方程, 想要计算从 ( i, j ) 位置出发到达终点时的最低初始血量, 就需要先计算它的前一个位置和下一个位置的最低初始血量. 因此以下位置在填表时不进行初始化就会导致填表发生越界错误.
image.png
因此, 这些位置在进行填表之前, 都是我们需要进行初始化的. 同样, 我们还是采取新增一行一列的办法, 将初始化的内容放在填表当中. 但此时不是和之前一样, 左边添加一列上面添加一行, 而是下面添加一行最后面添加一列
image.png

  1. 当填写这个位置的值时

由于它受到向右和向下两个位置的最小初始血量影响. 但是这两个位置是我们新开的. 它不应该影响我们要填的这个位置的值.

如果要填的这个红星的位置值为 0 的话, 显然是不对的. 这意味着你从这个地方出发的最低初始血量是 0, 而我们上面说了最低初始血量至少是 1. 而我们想要向右走或者向左走, 进去的最低血量就是 1, 可以理解为救完人后, 出来的最低血量至少是 1. 因此这两个位置的初始化结果为 1
image.png

  1. 填写其他位置的值时

当初始化其他位置的时候,这个时候要填写的位置除了受到新增位置的影响还受到原本矩阵内容的影响. 而我们新增的这些位置不能影响原本的数据. 根据状态转移方程取得是这两个方向上值的最小值. 因此新增的位置的值初始化为无穷大就不会影响我们填写的最终结果了.
image.png

5. 填表顺序

可以看到, 填写 ( i, j ) 位置时, 需要依赖它的后一个和下一个位置的值. 因此我们填表的顺序为 从下到上填写每一行, 而每一行又从右往左填写

6. 返回值

题目要求返回到达 ( m, n ) 位置时的最低初始血量. 而我们的状态表示为从某个位置开始到达终点时所需要的最低初始血量. 也就是 dp[0][0].文章来源地址https://www.toymoban.com/news/detail-509775.html

7. 代码演示

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {

        // 1. 创建 dp 表
        int m = dungeon.length;
        int n = dungeon[0].length;
        int[][] dp = new int[m + 1][n + 1];

        // 2. 初始化 
        // 将最后一行初始化为无穷大
        for(int j = 0; j <= n; j++) {
            dp[m][j] = Integer.MAX_VALUE;
        }
        // 将最后一列初始化为无穷大
        for(int i = 0; i <= m; i++) {
            dp[i][n] = Integer.MAX_VALUE;
        }
        // 将终点的右边和下边位置初始化为 1
        dp[m][n - 1] = dp[m - 1][n] = 1;

        // 3. 填写 dp 表, 从下往上每一行, 每一行从右往左
        for(int i = m - 1; i >= 0; i--) {
            for(int j = n - 1; j >= 0; j--) {

                // 根据状态转移方程填写
                // 虽然多开了一行一列, 但是对应到原本的 dungeon 的位置没变. 
                // 因为添加的位置是在最后一行和最后一列.
                dp[i][j] = Math.min(dp[i][j + 1], dp[i + 1][j] ) - dungeon[i][j];

                // 如果最终的结果太小为负数, dp 表中表示某个位置为起点的最低初始血量至少大于 1
                // 因此要对这个最终结果进行处理
                dp[i][j] = Math.max(1, dp[i][j]);
            }
        }
        
        // 4. 确认返回值
        return dp[0][0];
    }
}

到了这里,关于动态规划之地下城游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【动态规划算法】第十题:174.地下城游戏

    💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 今天我开始讲解动态规划第十题,也是路径问题的最后一

    2024年02月13日
    浏览(34)
  • 【动态规划专栏】专题二:路径问题--------6.地下城游戏

    本专栏内容为:算法学习专栏,分为优选算法专栏,贪心算法专栏,动态规划专栏以及递归,搜索与回溯算法专栏四部分。 通过本专栏的深入学习,你可以了解并掌握算法。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:动态规划专栏 🚚代码仓库:小小unicorn的代码仓库🚚

    2024年02月22日
    浏览(52)
  • 【动态规划刷题 5】 最小路径和&&地下城游戏

    链接: 64. 最小路径和 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 输入:grid = [[1,3,1],[1,5,1],[4,2,1]] 输出:7 解释:因为路径 1→3→1→1→1 的总和最小。 示例 2: 输入

    2024年02月13日
    浏览(35)
  • 【Leetcode每日一题】 动态规划 - 地下城游戏(难度⭐⭐⭐)(61)

    1. 题目解析 题目链接:174. 地下城游戏 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 一、状态表定义 在解决地下城游戏问题时,我们首先需要对状态进行恰当的定义。一个直观的想法是,从起点开始,到达[i, j]位置时所需的最低初始

    2024年04月29日
    浏览(35)
  • 【动态规划】【 矩阵】【逆向思考】C++算法174地下城游戏

    视频算法专题 动态规划汇总 矩阵 逆向思考 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数

    2024年02月03日
    浏览(39)
  • 【动态规划上分复盘】这是你熟悉的地下城游戏吗?

    本文讲解关于动态规划思路的两道题目。 1.确定状态表示(确定dp数组的含义) 2.确定状态转移方程(确定dp的递推公式) 3.确定如何初始化(初始化要保证填表正确) 4.确定遍历顺序 5.返回值 点我直达~ 根据题目可知,每一个位置都对应这三种情况: (d[i][j]由题目给出。)

    2024年02月12日
    浏览(32)
  • 【算法】动态规划 ⑦ ( LeetCode 55. 跳跃游戏 | 算法分析 | 代码示例 )

    LeetCode 55. 跳跃游戏 : https://leetcode.cn/problems/jump-game/ 给定一个 非负整数数组 nums ,你最初位于数组的 第一个下标 0 位置 。 数组中的每个元素 代表你在该位置可以 跳跃的最大长度。 判断你 是否能够到达最后一个下标。 给定一个一维数组 , 数组元素不能有负数 , 如 : {2, 2,

    2024年02月10日
    浏览(29)
  • 【算法】——动态规划题目讲解

    本期继续为大家带来的是关于动态规划类题目的讲解,对于这类题目大家一定要多加练习,争取掌握。 链接如下: 62. 不同路径 题目如下: 算法思路: 1. 状态表⽰:  对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式: i. 从 [i, j] 位置出发; ii. 从起始位置出发

    2024年02月10日
    浏览(29)
  • 动态规划题目练习

    动态规划背包问题-CSDN博客 动态规划基础概念-CSDN博客 题目描述 棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河

    2024年04月25日
    浏览(25)
  • 动态规划2:题目

    目录 第1题 Fibonacci 第2题 字符串分割(Word Break) .第3题 三角矩阵(Triangle) 第4题 路径总数(Unique Paths) 第5题 最小路径和(Minimum Path Sum) 第6题 背包问题 第7题 回文串分割(Palindrome Partitioning) 第8题 编辑距离(Edit Distance) 第9题 不同子序列(Distinct Subsequences) 分析问题: 1. 状态定义F(i):第

    2024年02月06日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包