【每日易题】Leetcode上Hard难度的动态规划题目——地下城游戏的实现

在这里插入图片描述

君兮_的个人主页

即使走的再远,也勿忘启程时的初心

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,博主最近一直在钻研动态规划算法,最近在Leetcode上刷题的时候遇到一个Hard难度的动态规划题,今天就借此机会来给大家分享一下我对这个题目的一些看法和解题思路(放心,我是AC了的)

  • 好了废话不多说,开始我们今天的学习吧!!

地下城游戏

  • Leetcode上的原题链接在这里:地下城游戏

在这里插入图片描述

在这里插入图片描述

  • 好好好,一看题目里一大堆字还看不懂它到底什么意思,再看看上面标的hard难度,一大堆人相信和博主一样上来就准备先点击退出了,大家先不要捉急,我来带大家一步一步分析一下这个题目的意思

题目解析

在这里插入图片描述
(ps:这个在漫画里真是公主)

  • 我们的公主被抓住关在了最右下角,如图所示
    在这里插入图片描述
  • 接下来,我们的骑士要从图中位置出发,其中遇到恶魔(也就是格子里的值为负值)就需要与它们战斗会扣血,当遇到魔法球(图中为正值),就可以回血。此时,题目问我们,在初始位置时,骑士至少需要多少血(规定当在某个位置血量大于等于1即可通过否则失败)
  • 那么,通过题目的描述,结合之前我们学过的动态规划思想,你发现什么不一样了吗?作为Hard难度的题,想用常规的思维来解决肯定是不可能的,好了,接下来我带大家具体分析一下其中的算法原理吧

算法原理

1. 状态表示

  • 我们之前在动态规划的算法中说过,遇到动态规划问题时,一般的解决方式就是分两种情况:
    • (1) 选择某一个位置为终点结束,建立dp表,进行状态表示
    • 2)选择某一个位置为起点出发…
  • 按照常规思路,我们既然知道了公主的位置,那正常情况就是选择第一种情况来试着进行状态表示
  • 这道题如果我们照着这个思路定义成:从起点开始,到达[i, j] 位置的时候,所需的最低初始健康点数。
  • 那么我们分析状态转移的时候会有⼀个问题:那就是我们当前的健康点数还会受到后面的路径的影响。也就是从上往下的状态转移不能很好地解决问题。

这里是为什么呢?我们设想一下,假设此时我们骑士的血很少,下一格无论是朝下还是朝右都会遇到恶魔把我们骑士的血扣为负数,那此时这里的dp值合理吗?很显然是不合理的。因此我们出了考虑前面位置的情况,还要考虑后面路径的情况,岂不是太麻烦了?

  • 这个时候我们要换⼀种状态表示:从[i, j] 位置出发,到达终点时所需要的最低初始健康点数。这样我们在分析状态转移的时候,前面的路径不需要考虑,后续的最佳状态已经知晓,这样就极大的简化了我们分析的难度。

  • 综上所述,定义状态表示为:
    dp[i][j] 表示:从[i, j] 位置出发,到达终点时所需的最低初始健康点数


2 状态转移方程

  • 对于 dp[i][j] ,从 [i, j] 位置出发,下⼀步会有两种选择(为了方便理解,设 dp[i][j] 的最终答案是 x):

  • i. ⾛到右边,然后⾛向终点

  • 那么我们在 [i, j] 位置的最低健康点数加上这⼀个位置的消耗,应该要⼤于等于右边位置的最低健康点数,也就是: x + dungeon[i][j] >= dp[i][j + 1] 。
    通过移项可得: x >= dp[i][j + 1] - dungeon[i][j] 。因为我们要的是最⼩值,因此这种情况下的 x = dp[i][j + 1] - dungeon[i][j]

  • ii. ⾛到下边,然后⾛向终点

  • 那么我们在 [i, j] 位置的最低健康点数加上这⼀个位置的消耗,应该要⼤于等于下边位置的最低健康点数,也就是: x + dungeon[i][j] >= dp[i + 1][j] 。
    通过移项可得: x >= dp[i + 1][j] - dungeon[i][j] 。因为我们要的是最⼩值,因此这种情况下的 x = dp[i + 1][j] - dungeon[i][j]

  • 综上所述,我们需要的是两种情况下的最⼩值,因此可得状态转移⽅程为:
    dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]

  • 但是,如果当前位置的 dungeon[i][j] 是⼀个⽐较⼤的正数的话, dp[i][j] 的值可能变成 0 或者负数。也就是最低点数会⼩于 1 ,那么骑⼠就会死亡。因此我们求出来的 dp[i][j] 如果⼩于等于 0 的话,说明此时的最低初始值应该为 1 。处理这种情况仅需让 dp[i][j] 与 1 取⼀个最⼤值即可:
    dp[i][j] = max(1, dp[i][j])

什么意思呢?就是这里的[i,j]会给恢复一大口血,但是如果此时的dp[i,j]为负数的时候,说明此时这里要求的骑士的最低血量是0或者负数,这显然是不符合要求的,因此我们需要对这种特殊情况进行一下上述的这种处理

初始化

  • 可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
  • i. 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  • ii. 「下标的映射关系」。

有关辅助节点的使用方法在上面链接的博客中讲过了,这里就不再详叙

  • 在本题中,由于我们要考虑后面路径对现在位置的影响,需要在dp表最后面添加一行,并且添加⼀列后,所有的值都先初始化为无穷大,然后让dp[m][n - 1] 或dp[m - 1][n] = 1 即可。

填表顺序

  • 根据「状态转移方程」,我们需要「从下往上填每一行」,「每一行从右往左填」。看了上面的算法分析这一点应该不难理解

返回值

  • 从题目中可知,我们的骑士是从左上角开始的,因此结合上述分析,我们需要返回的值为dp[0][0]

编写代码

class Solution {
public:int calculateMinimumHP(vector<vector<int>>& dungeon) {int m=dungeon.size();int n=dungeon[0].size();//建立dp表,以某个位置为开始建立状态转移方程vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));dp[m][n-1]=1;//考虑边界问题for(int i=m-1;i>=0;i--){for(int j=n-1;j>=0;j--){//填表dp[i][j]=min(dp[i+1][j],dp[i][j+1])-dungeon[i][j];dp[i][j]=max(1,dp[i][j]);}}//返回值return dp[0][0];}
};
  • 代码很简单,只有十几行,实际上难的是上面分析题目的过程以及对一些特殊情况的判断,代码这里相信如果你能看懂上述原理的分析,这点对你来说应该一点都不难。

总结

  • 好啦,我们今天的内容就先到这里啦!其实代码并不重要,能看懂背后隐藏的原理并且通过这个题目学会对应题目的分析才重要,因此如果你想真正学会的话,不妨自己从头试着理解一下算法原理再自己独立编写代码,这样我相信是最能提升自己有关动态规划题目的理解的。
  • 有任何的问题和对文章内容的疑惑欢迎在评论区中提出,当然也可以私信我,我会在第一时间回复的!!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/198567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

品牌保护与知识产权:跨境电商中的法律挑战与解决方案

随着跨境电商的蓬勃发展&#xff0c;品牌保护和知识产权问题日益成为业界关注的焦点。在全球范围内进行电商业务&#xff0c;涉及到多国法律法规的复杂性&#xff0c;品牌所有者需要面对一系列法律挑战&#xff0c;保护其品牌和知识产权不受侵害。本文将深入探讨跨境电商中面临…

L1-016:查验身份证

题目描述 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff0c;8&#xff0c;4&#xff0c;2&#xf…

P1 Orange Pi Zero2镜像烧录和环境搭建(换源)

目录 前言 01 镜像下载 02 镜像烧录 03 SD卡启动 04 SSH登录开发板 05 基于官方外设开发 方法1 方法2 前言 此专栏为智能家居项目&#xff0c;使用的开发板一共有三块&#xff0c;分别为 主控&#xff1a;Orange Pi Zero2触摸屏控制面板&#xff1a;i.MX 6ULL子系统&…

字符指针变量数组指针变量

字符指针变量 在指针的类型中&#xff0c;我们知道有一种指针叫做字符指针 一般的使用情况如下&#xff1a; #include<stdio.h> int main() {char ch w;char* pa &ch;*pa h;printf("%c", *pa);return 0; } 还有一种使用方法如下&#xff1a; #incl…

国内 AI 成图第一案!你来你会怎么判?

我国目前并未出台专门针对网络爬虫技术的法律规范&#xff0c;但在司法实践中&#xff0c;相关判决已屡见不鲜&#xff0c;K 哥特设了“K哥爬虫普法”专栏&#xff0c;本栏目通过对真实案例的分析&#xff0c;旨在提高广大爬虫工程师的法律意识&#xff0c;知晓如何合法合规利用…

室内外融合便携式定位终端5G+UWB+RTK

一、介绍 便携式定位终端主要用于提供高精度的位置数据&#xff0c;支持室内UWB定位和室外北斗系统定位功能&#xff0c;支持5G公网和5G专网通信功能&#xff0c;便携式定位终端中超宽带(UWB)和实时动态(RTK)技术的集成代表了精确位置跟踪方面的重大进步。这款UWBRTK便携式定位…

git 本地改动无法删除

1. 问题 记录下git遇到奇怪的问题&#xff0c;本地有些改动不知道什么原因无法删除 git stash&#xff0c; git reset --hard HEAD 等都无法生效&#xff0c;最终通过强制拉取线上解决 如下图&#xff1a; 2. 解决 git fetch --all git reset --hard origin/master执行这两…

Android RatingBar实现五星好评

属性 isIndicatorRatingBar 是否为指示器&#xff0c;为true时&#xff0c;用户将无法交互操作&#xff0c;默认为false。 numStars 显示的星型数量&#xff0c;必须是一个整形值&#xff0c;像“50”&#xff0c;虽然可以设置很大&#xff0c;但一般…

STM32-新建工程(标准库)

目录 STM32F10x新建工程&#xff08;标准库&#xff09; 移植文件夹 新建工程 添加启动文件和必需文件 在工程中加载新添加的文件 在工程中添加文件路径 在工程中添加main函数 添加lib库 添加必需文件 添加宏定义 STM32F10x新建工程&#xff08;标准库&#xff09; …

【Python】创建简单的Python微服务Demo与FastAPI

创建简单的Python微服务Demo与FastAPI 在微服务架构中&#xff0c;通过FastAPI框架创建一个简单的Python微服务Demo涉及多个步骤&#xff0c;包括定义服务、使用框架、进行通信等。在这篇文章中&#xff0c;我们将使用FastAPI框架创建两个简单的微服务&#xff0c;它们通过RES…

HBase安装配置:一键自动安装配置

使用shell脚本一键下载、安装、配置HBase&#xff08;单机版&#xff09; 1. 把下面的脚本复制保存为/tmp/install_hbase.sh文件 #!/bin/bash# 安装之前确保安装目录有写入权限&#xff0c;若没有&#xff0c;自行增加 # 安装版本 zk_version"2.4.8" # 安装目录 zk…

【WxPusher】消息推送小案例

提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 WxPusher后台 WxPusher文档 一、注册WxPusher 进入后台获取你的token 二、使用步骤 1.编写脚本 参数如下&#xff08;示例&#xff09;&#xff1a; {"appToken": "AT_AnXubGNGCe7OVN…

基于springboot的校园二手市场

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

LeetCode:2477. 到达首都的最少油耗(DFS C++、Java)

目录 2477. 到达首都的最少油耗 题目描述&#xff1a; 实现代码与解析&#xff1a; dfs 2477. 到达首都的最少油耗 题目描述&#xff1a; 给你一棵 n 个节点的树&#xff08;一个无向、连通、无环图&#xff09;&#xff0c;每个节点表示一个城市&#xff0c;编号从 0 到 n…

医院预约挂号平台的设计与实现

摘 要 网络的空前发展给人们的工作和生活带来了极大的便利&#xff0c;信息技术已成为节约运营成本、提高工作效率的首选。相比之下&#xff0c;国内相当多的中小医院在医院预约工作中的手工工作比较保守&#xff0c;数据查询和存储成本都很高&#xff0c;但效率很低。为了使医…

JAVAEE初阶 多线程基础(六)

wait,notify,饿汉模式 一.wait,notify方法使用1.1 例子 二.wait和sleep区别三.单例模式中的饿汉模式 一.wait,notify方法使用 引入wait和notify为了能够从应用层面上,干预到多个不同线程代码的执行顺序,不是影响系统的线程调度策略. 相当于是在应用程序代码中,让后执行的线程,主…

支付宝沙箱支付

1. 二维码 1.1 什么是二维码&#xff1a; ​ 二维码又称QR Code&#xff0c;QR全称Quick Response&#xff0c;是一个近几年来移动设备上超流行的一种编码方式&#xff0c;它比传统的Bar Code条形码能存更多的信息&#xff0c;也能表示更多的数据类型。 ​ 二维条码/二维码&…

HNU-电路与电子学-2017期末B卷(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程&#xff0c;故实际上目前只有2020与2021两个年级考过期末考试。 这门课程主要由所谓的“数电”与“模电”组成。而且先学的“模电”后学的“”数电&#xff0c;故期中考试主要以“模电”为主&#xff0c;期末考试主要以“…

04数据平台Flume

Flume 功能 Flume主要作用&#xff0c;就是实时读取服务器本地磁盘数据&#xff0c;将数据写入到 HDFS。 Flume是 Cloudera提供的高可用&#xff0c;高可靠性&#xff0c;分布式的海量日志采集、聚合和传输的系统工具。 Flume 架构 Flume组成架构如下图所示&#xff1a; A…

编译原理:NFA转DFA(原理+完整代码+可视化实现)

NFA转换为DFA 【本文内容摘要】 什么是DFA通过子集构造法将NFA转换为DFA生成DFA的dot文件并且形成可视化。 如果本文对各位看官有用的话&#xff0c;请记得给一个免费的赞哦&#xff08;收藏也不错&#xff09;&#xff01; 文章目录 NFA转换为DFA一、什么是DFA二、NFA转换为…