动态规划第二弹:路径类问题(不同路径,珠宝的最高价值,地下城游戏)

article/2025/7/23 2:29:02

目录

前言

1. 不同路径

(1)题目及示例

(2)解题思路

(3)代码

2. 珠宝的最高价值

(1)题目及示例

(2)解题思路

(3)代码

3. 地下城游戏

(1) 题目及示例

(2)解题思路

(3)代码


前言

本文将讲解三道关于动态规划路径类型的题目,难度依次上升。解题思路部分图文并茂,希望对你有所启发。


1. 不同路径

(1)题目及示例

题目链接:62. 不同路径 - 力扣(LeetCode)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?

示例1:

输入:m = 3,n = 7

输出:28

示例2:

输入:m = 3, n = 2
输出:3
解释:从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

示例3:

输入:m = 3, n = 3
输出:6

(2)解题思路

如果使用动态规划来解题,就得先根据题目给出状态转移方程。根据以往的经验,都是以某个位置为结尾,来定义状态转移方程。

  • 我们可以定义 dp[i][j] 表示,当机器人走到 (i,j) 位置时,一共有多少种方式。
  • 下图中,当机器人走到三角的位置,他只可能从上面和左边走到该位置,而上面和左边位置的总的路径数量分别是 dp[i][j-1] 和 dp[i-1][j]。那么三角位置路径数量就是上面和左边位置路径数量之和。即 dp[i][j] dp[i][j-1] + dp[i-1][j]

这道题的核心部分已经讲完,接下来讲一下细节处理问题。

  • 因为当前位置的dp值需要二维数组上面和左边的dp值进行赋值,所以第一行和第一列的元素,如果按照状态转移方程赋值,会发生越界。
  • 但是第一行第一列的dp值手动初始化,就太麻烦。
  • 因此,可以在原二维矩阵上,多加上一行和一列,从下标 (1, 1) 位置开始处理,就不会越界。
  • 不过多加的一行和一列元素如何初始化,这需要根据题目来定。首先,(1, 1) 位置的dp值一定为1,所以它上面或者左边的元素其中一个初始化为1即可。剩下的元素全部初始化为0。

(3)代码

class Solution {
public:int uniquePaths(int m, int n) {// 创建dp表,多加一行和一列vector<vector<int>> dp(m + 1, vector<int>(n + 1));   // 初始化值dp[0][1] = 1;// 填表for(int i = 1; i <= m; i++)  // 从上往下遍历每一行for(int j = 1; j <= n; j++)  // 从左往右遍历每一行dp[i][j] = dp[i-1][j] + dp[i][j-1];return dp[m][n];}
};

2. 珠宝的最高价值

(1)题目及示例

题目链接:LCR 166. 珠宝的最高价值 - 力扣(LeetCode)

现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为:

  •     只能从架子的左上角开始拿珠宝
  •     每次可以移动到右侧或下侧的相邻位置
  •     到达珠宝架子的右下角时,停止拿取

注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]。

示例 1:

输入:frame = [ [1,3,1], [1,5,1], [4,2,1]]
输出:12
解释:路径 1→3→5→2→1 可以拿到最高价值的珠宝

(2)解题思路

这道题目跟不同路径类似,不过需要具体分析题目要求。

  • 我们可以定义 dp[i][j] 表示,当从 (0, 0) 走到 (i,j) 位置时,珠宝最高价值的总数。
  • 走到红色三角位置前,有两种方式,一种是从上面来,另外一种是从左边来,但是我们统计的是珠宝的最高价值,所以是比较 (i, j - 1) (i - 1, j) 位置的珠宝价值,最后加上(i,j) 位置的珠宝价值。
  • 所以状态转移方程为 dp[i][j] = max(dp[i][j - 1],  dp[i - 1][j]) + frame[i][j]

状态转移方程分析写出来后,需要处理细节问题。

  • 跟之前题目类似,第一行和第一列元素进行动态规划时,会越界。所以需要进行手动初始化,但是手动初始化比较麻烦。
  • 因此,在原二维数组的基础上,多添加上一行和一列元素。
  • 根据状态转移方程,全部初始化为0即可,这样不会影响原数组第一行第一列元素的赋值。

(3)代码

class Solution {
public:int jewelleryValue(vector<vector<int>>& frame) {// 创建dp表,多加上一行和一列int m = frame.size(), n = frame[0].size();// 默认初始化为0,所以不用单独赋值vector<vector<int>> dp(m + 1, vector<int>(n + 1));for(int i = 1; i <= m; i++) // 从上往下遍历每一行for(int j = 1; j <= n; j++) // 从左往右遍历每一行dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + frame[i-1][j-1];return dp[m][n];}
};

3. 地下城游戏

(1) 题目及示例

题目链接:174. 地下城游戏 - 力扣(LeetCode)

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

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

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

为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。返回确保骑士能够拯救到公主所需的最低初始健康点数。

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

示例1:

输入:dungeon = [ [-2,-3,3], [-5,-10,1], [10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

示例 2:

输入:dungeon = [[0]]
输出:1

(2)解题思路

这道题在Leetcode中难度是困难级别,我们尝试分析一下解题思路。

根据前两道做题经验,我们可以试着定义状态转移方程。定义 dp[i][j] 为从起点出发,到 (i,j) 位置结束,所需的最小健康点数。

  • 在绿色三角 (i,j) 的位置,骑士可以从上面和左边走过来,那么需要上面和左边健康点数中的较小值,并减去当前房间的数值。
  • 可是绿色房间的数值如果很小,就有可能导致健康点数变成负数。如果经过绿色房间后,健康点数大于0。
  • 但是从(i,j) 的位置往下走或者往右走,可能会遇到房间数值是个很小的负数,导致绿色房间。

所以说,这种定义方式,写出的状态转移方程需要考虑后面的值。

从前往后的定义方式不行,我们可以换一种方式,从后往前。定义 dp[i][j] 为从(i,j) 位置开始,到终点右下角的房间结束,所需的最小健康点数。

  • 骑士从绿色房间出发,可以往下面和右边的房间走,假设往右边的房间走,(i,j) 位置的健康点数加上该位置的数值,要大于等于(i,j - 1) 位置的健康点数。
  • dp[i][j] + d[i][j] >= dp[i][j - 1],解一下不等式,dp[i][j] >= dp[i][j + 1] - d[i][j]。同理走下面的房间,也会得到类似的式子 dp[i][j] >= dp[i +1][j] - d[i][j]

  • 我们要的是健康点数的最小值,所以要取dp[i][j + 1]dp[i + 1][j] 中的较小值。
  • 最后,如果d[i][j]的数值是一个很大的整数,导致dp[i][j]变成负数,。因为骑士健康点数小于等于0的情况下无法继续走下去,所以需要改成最小健康点数1。

最后处理细节问题,这次我们填表的顺序是从下往上,从左往右。

因此,多加的一行和一列在后面。靠近原数组右下角位置的右边和下面的元素,需要初始化为1。其余的初始化为正无穷。

(3)代码

    int calculateMinimumHP(vector<vector<int>>& d) {// 创建dp表,多加上一行和一列int m = d.size(), n = d[0].size();vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));// 初始化两个位置的值为1dp[m][n-1] = dp[m-1][n] = 1;for(int i = m - 1; i >= 0; i--) // 从下往上遍历每一行for(int j = n - 1; j >= 0; j--) // 从右往左遍历每一行dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1]) - d[i][j]);return dp[0][0];}


创作充满挑战,但若我的文章能为你带来一丝启发或帮助,那便是我最大的荣幸。如果你喜欢这篇文章,请不吝点赞、评论和分享,你的支持是我继续创作的最大动力!


http://www.hkcw.cn/article/KYTSsGWWiF.shtml

相关文章

LabVIEW双光子显微镜开发

基于LabVIEW 开发高性能双光子显微镜系统&#xff0c;聚焦于生物样本深层成像与纳米材料三维表征。实现了超快激光控制、多维数据采集与实时图像重建。系统采用飞秒激光光源与高精度振镜扫描模块&#xff0c;结合 LabVIEW 的 FPGA 实时控制能力&#xff0c;可对活体组织、荧光纳…

C++校园植树节活动 全国信息素养大赛复赛决赛 C++小学/初中组 算法创意实践挑战赛 内部集训模拟题详细解析

C++校园植树节活动 全国信息素养大赛 C++复赛/决赛模拟训练题 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】1、C++专栏 电子学会C++一级历年真题解析电子学会C&#

题海拾贝:压缩字符串

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

Golang——3、流程控制语句

流程控制语句 1、if-else(分支语句)2、for(循环语句)3、for range(键值循环)4、switch-case(分支语句)5、break跳出循环6、continue(跳过本次循环)7、goto(跳转到指定标签) Go语言中最常用的流程控制有if和for&#xff0c;而switch和goto主要是为了简化代码、降低重复代码而生的…

第14讲、Odoo 18 实现一个Markdown Widget模块

目录 模块概述安装与配置前端实现详解依赖库分析使用示例与最佳实践技术架构与设计模式分析总结 模块概述 模块地址https://apps.odoo.com/apps/modules/18.0/web_widget_markdown Odoo 18 Markdown Widget 是一个为 Odoo 18.0 社区版开发的全局通用模块&#xff0c;它允许…

乌方袭击俄机场画面曝光 乌克兰最大胆军事行动

乌克兰官员周日宣布,乌克兰军队对俄罗斯境内深处的多个军用机场发动了大规模无人机袭击。这些机场是用于进行空袭的战略轰炸机基地,这次行动被认为是自俄乌冲突爆发以来乌克兰军队最大胆的军事行动之一。乌克兰安全局官员透露,此次代号为“蛛网”的袭击行动历时一年半准备。…

22. Generate Parentheses

题目描述 22. Generate Parentheses 回溯法 class Solution {vector<string> res;string cur; public:vector<string> generateParenthesis(int n) {backtrack(n,0,0);return res;}void backtrack(int n,int left_count,int right_count){if(cur.size() 2*n){…

DRW - 加密市场预测

1.数据集描述 在本次比赛中&#xff0c;数据集包含加密市场的分钟级历史数据。您的挑战是预测未来的加密货币市场价格走势。这是一项kaggle社区预测竞赛&#xff0c;您可以以 CSV 文件的形式或通过 Kaggle Notebooks 提交您的预测。有关使用 Kaggle Notebooks 的更多详细信息&a…

Pcie6.0连接器协会规格及测试要求

Pcie6.0连接器协会规格及测试要求&#xff1a; 4 GT/s 原始数据速率和高达 256 GB/s&#xff08;通过 x16 配置&#xff09;。 具有 4 级 (PAM4) 信号的脉冲幅度调制&#xff0c;并利用行业中已有的现有 PAM4。 轻量级前向纠错 (FEC) 和循环冗余校验 (CRC) 可减轻与 PAM4 信令…

VSCODE

keil环境配置 插件安装配置 Embedded IDE插件&#xff1a;编译stm32 &#xff0c;nxp等芯片 进入Embedded IDE配置&#xff1a;keil 配置配置下载参数 安装工具 烧录工具 烧录配置 gcc编译工具 下载最新的gcc&#xff1a;GCC 下载安装-CSDN博客GCC 下载安装-CSDN博客GCC 下载…

PgMP管理过程交付物-相关方参与计划

相关方参与计划&#xff1a; 4W1H相关方参与计划What(做什么)项目集收益移交计划规定了项目集相关方在整个项目集持续期间将如何参与Why(为什么做)项目集相关方参与规划规定了项目集相关方在整个项目集持续期间将如何参与Who(谁来做) 负责人&#xff1a;项目集经理 批准&#…

【MySQL】索引特性

文章目录 一、初始索引二、MySQL与储存三、软件理解四、Page五、聚簇/非聚簇索引六、索引操作1.创建主键索引2.创建唯一索引3.创建普通索引4.查询索引5.删除索引 一、初始索引 索引的核心工作是提高数据库性能的&#xff0c;MySQL的服务器&#xff0c;本质是在内存中的&#x…

机器学习----决策树

一、决策树简介 from sklearn.tree import DecisionTreeClassifier from sklearn.tree import plot_tree 决策树是一种树形结构&#xff0c;树中每个内部节点表示一个特征上的判断&#xff0c;每个分支代表一个判断结果的输出&#xff0c;每个叶子节点代表一种分类结果。 决…

天问二号问天之旅第一站拜访谁 探秘地球准卫星

我国行星探测工程天问二号探测器在西昌卫星发射中心成功发射,开启了“问天”之旅。这次任务的目标之一是小行星2016HO3。根据命名规则,这个名称包含了发现年份、时间段和顺序的信息。选择探测小行星2016HO3的原因在于它保留了太阳系诞生之初的原始信息,是研究太阳系早期物质…

WebStorm创建文件和目录

目录 创建文件和目录创建空文件从模板创建文件创建目录 创建文件和目录 创建空文件 在“项目”工具窗口中&#xff0c;选择要在其中创建文件的目录&#xff0c;按 Alt Insert&#xff0c;然后从列表中选择“File”。在打开的“New File”对话框中&#xff0c;输入文件名和扩…

【js逆向】信息公示平台搜索滑块逆向

目标&#xff1a;实现搜索后&#xff0c;滑块验证&#xff0c;得到结果。 网站&#xff1a;aHR0cHM6Ly94eGdzLmNoaW5hbnBvLm1jYS5nb3YuY24vZ3N4dC9uZXdMaXN0 1. 输入搜索关键字&#xff0c;触发滑块验证 a和b后面要用到的参数&#xff0c;c中的cutImage和oriImage是背景和缺口…

笔试模拟 day16

观前提醒&#xff1a; 笔试所有系列文章均是记录本人的笔试题思路与代码&#xff0c;从中得到的启发和从别人题解的学习到的地方&#xff0c;所以关于题目的解答&#xff0c;只是以本人能读懂为目标&#xff0c;如果大家觉得看不懂&#xff0c;那是正常的。如果对本文的某些知…

AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月1日第95弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀4-5个和值&#xff0c;可以做到100-300注左右。 (1)定…

AgentThink:在自动驾驶的一个统一框架,视觉-语言模型中工具增强的思维链推理

25年5月来自清华大学、Mcgill大学、小米公司和 Wisconsin&#xff08;Madison&#xff09;大学的论文“AgentThink: A Unified Framework for Tool-Augmented Chain-of-Thought Reasoning in Vision-Language Models for Autonomous Driving”。 视觉语言模型 (VLM) 在自动驾驶…

印度男子泰国景区摸老虎屁股遭扑咬 不当抚摸惹怒老虎

近日,一名印度游客在泰国普吉岛的热门景点被老虎袭击。视频中能听到现场惨叫声不断,拍摄画面也变得晃动模糊。据视频发布者称,该男子受了轻伤,成功逃脱。有网友指出,猫科动物通常不喜欢被抚摸背部尤其是靠近臀部的位置,这种行为可能让老虎感到不适。在泰国一些景区,游客…