【动态规划篇】:动态规划解决路径难题--思路,技巧与实例

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:动态规划篇–CSDN博客

在这里插入图片描述

文章目录

  • 一.动态规划中的路径问题
    • 1.核心思路
    • 2.注意事项
  • 二.例题讲解
    • 1.不同路径
    • 2.不同路径2
    • 3.珠宝的最高价值
    • 4.最小路径和
    • 5.下降路径最小和
    • 6.地下城游戏

一.动态规划中的路径问题

动态规划中的路径问题通常涉及在网格或图中寻找最优路径,如最短路径,路径数目或者最大和最小和路径等。

1.核心思路

  • 状态表示:

    如果是由前状态推导出后状态,dp[i] [j]表示以[i,j]为终点,到达该位置的状态(如路径个数,最小和或者最大和等);如果是由后状态推出前状态,dp[i] [j]表示以[i,j]为起点,到达终点的状态(如路径个数,最小和或者最大和等)。

  • 状态转移方程:

    如果是由前状态推导出后状态,找到当前位置[i,j]可以通过哪些下标达到,也就是前一个状态;如果是由后状态推出前状态,找到当前位置[i,j]可以达到哪些下标,也就是后一个状态。不同类型的路径问题的状态转移方程格式也不同,需要根据题意来决定。

  • 初始化:

    根据状态转移方程方程处理边界条件,防止越界或者状态值出现误差,因为数组下标从0开始,所以通常在处理状态表时,添加第0行和第0列作为虚拟下标,部分题中可能还需要添加最后一行或者最后一列,需要根据题意来决定。

  • 填表顺序:

    通常就是两种情况,因为状态表是二维数组,如果是由前状态推导出后状态,从第一行到最后一行,其中每一行的顺序是从左往右;如果是由后状态推出前状态,从最后一行到第一行,其中每一行的顺序是从右往左。

  • 返回值:

    根据题意决定,假设以网格中最右下角[m,n]为终点,如果是由前状态推导出后状态,返回dp[m] [n];如果是由后状态推导出前状态,返回dp[0] [0]。

2.注意事项

简单总结一下,动态规划处理路径问题中需要注意一下几点:

  • 状态表示是否合理,能否覆盖所有可能的路径情况。

  • 状态转移方程是否正确,是否覆盖了当前位置所有的移动方向。

  • 初始化是否正确,特别是边界处理,如果添加虚拟下标,能否保证后面边界状态值的正确以及下标的映射是否对应。

  • 特殊情况的处理,比如当前路径上存在障碍,起点终点不可达等情况。

路径问题的动态规划“大多”都是涉及到二维数组,因此在学习路径问题时建议先了解涉及一维数组的简单练习题,比如斐波那契数列模型的动态规划类题,有了前面的经验,在处理二维数组的问题时,状态表示和状态转移方程其实就能更好理解,个人认为,路径问题涉及的难点在于对初始化的处理,也就是边界处理,所以在接下来的例题讲解中会重点讲解每道题的边界处理情况。

二.例题讲解

1.不同路径

题目

在这里插入图片描述
在这里插入图片描述

算法原理

本道题就是典型的路径个数问题,这里用前状态推导出后状态的方式来定义状态表示,dp[i] [j]表示以[i,j]为结尾 到达该位置的路径总数,填表顺序就是从第一行到最后一行,其中每一行的顺序是从左往右,题意要求右下角为终点,所以最后返回的是dp[m][n](m表示行数,n表示列数)。

根据题意要求,每次移动可以向下或者向右移动,因此想要到达下标[i,j]的位置有两种情况,一种是下标为[i-1,j]的位置向下移动(重复子问题,用dp[i-1] [j]表示);另一种是下标为[i,j-1]的位置向右移动(重复子问题,用dp[i] [j-1]表示),两种情况的路径和就是dp[i] [j]的值,因此状态转移方程就是dp[i] [j] = dp[i - 1] [j] + dp[i] [j - 1]

重点:初始化处理

在这里插入图片描述

代码实现

int uniquePaths(int m, int n){//状态表示 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.不同路径2

题目

在这里插入图片描述

在这里插入图片描述

算法原理

本道题也是属于路径个数问题,但是和上一道题不同的是,本题在网格中增加了障碍下标,也就是说可能会存在某些路径无法通过的情况。

本题的整体思路都和上一道题相同(包括初始化的处理)这里就不再重复讲解,唯一不同的是需要处理障碍下标对应的状态值,如果当前下标是障碍,说明不管上一个状态总共有多少种路径,遇到障碍就会全都不能通过,所以相当于路径变为0,因此障碍下标对应的状态值直接设置为0即可,不用再找前状态。

代码实现

int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid){int m = obstacleGrid.size(), n = obstacleGrid[0].size();//状态表示,dp[i][j]表示以[i,j]为结尾,到达该位置的路径总数,起点从[1,1]开始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++){//判断当前位置是否是障碍if(obstacleGrid[i-1][j-1]==1){dp[i][j] = 0;}else{//状态转移方程dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}}//返回值return dp[m][n];
}

3.珠宝的最高价值

题目

在这里插入图片描述

算法原理

根据题意要求,最后需要找到价值最高的路径,因此本道题属于路径问题中的最大和路径,同样这里还是用前状态推导出后状态,dp[i][j]表示以[i,j]为终点,到达该位置时的最高价值(最大和),填表顺序就是从第一行到最后一行,其中每一行的顺序是从左往右,题意要求右下角为终点,所以最后返回的是dp[m][n](m表示行数,n表示列数)。

根据题意要求,每次移动可以向下或者向右移动,因此想要到达下标[i,j]的位置有两种情况,一种是下标为[i-1,j]的位置向下移动(重复子问题,用dp[i-1] [j]表示到达[i-1][j]下标的最高价值);另一种是下标为[i,j-1]的位置向右移动(重复子问题,用dp[i] [j-1]表示表示到达[i][j-1]下标的最高价值),通过贪心策略每次移动都选择价值最高的那种情况然后加上当前下标[i][j]对应的价值(注意因为状态表添加了虚拟下标,起点从[1][1]开始,所以当前下标映射到价值数组时是下标[i-1][j-1])。

重点:初始化处理

在这里插入图片描述

代码实现

int jewelleryValue(vector<vector<int>>& frame){int m = frame.size(), n = frame[0].size();//状态表示 以[i,j]为结尾 dp[i][j]表示到达[i,j]位置时的最高价值 起点从[1,1]开始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];
}

4.最小路径和

题目

在这里插入图片描述

算法原理

本道题和上面那道最大和问题可以归为一类,并且本题和上一题的题意要求大致相同,所以整体思路还是大致相同(这里就不再过多重复),只不过本题需要找到的是最小和路径,所以相较于上一题,本题有两个地方需要修改。

第一个:因为需要找的是最小和,所以状态转移方程那里,根据贪心策略每次移动都选择最小和的那种情况,因此需要使用min函数取小的而不是取大的。

第二个:初始化处理时,上一道题需要使用max取较大的,所以虚拟下标对应的状态值用0填充,保证边界的状态值正确;而本题需要用min函数取较小的,所以虚拟下标对应的状态值用整形的最大值(INT_MAX)填充,这样才能保证边界的状态值正确,而这里还要将下标为[0][1]用0填充,保证起点下标的状态值正确。

代码实现

int minPathSum(vector<vector<int>>& grid){int m = grid.size(), n = grid[0].size();//状态表示,以[i,j]为结尾,dp[i][j]表示到达[i,j]位置时的最小路径和,起点从[1,1]开始vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));//初始化dp[0][1] = 0;//填表for (int i = 1; i <= m; i++){for (int j = 1; j <= n; j++){//状态转移方程dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];}}//返回值return dp[m][n];
}

5.下降路径最小和

题目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

算法原理

本道题和最小路径和是同一类问题,但是这道题有点不一样,起点和终点不再局限于左上角和右下角,而是起点变成第一行,终点变成最后一行,并且移动方向也不再是向下或者向右两种方向移动,而是变成了左下方向,正下方向,右下方向三种移动方向。

以下标[i,j]为结尾,dp[i][j]表示到达该位置时的最小路径和,有前状态推出后状态,填表顺序就是从第一行到最后一行,其中每一行的顺序是从左往右,注意因为最后一行中的每个下标都可以作为终点,所以在填完状态表后,遍历最后一行,找到最小路径和返回。

根据题意要求,每次移动可以向下,向左下或者向右下移动,因此想要到达下标[i,j]的位置有3种情况,第一种是下标为[i-1,j]的位置向下移动(重复子问题,用dp[i-1] [j]表示到达[i-1][j]下标的最小路径和);第一种是下标为[i-1,j-1]的位置向右下移动(重复子问题,用dp[i-1] [j-1]表示表示到达[i-1][j-1]下标的最小路径和);第三种是下标为[i-1,j+1]的位置向左下移动(重复子问题,用dp[i-1] [j+1]表示表示到达[i-1][j+1]下标的最小路径和);通过贪心策略每次移动都选择路径和最小的那种情况然后加上当前下标[i][j]对应的路径值(注意因为状态表添加了虚拟下标,起点从[1][1]开始,所以当前下标映射到路径值数组时是下标[i-1][j-1])。

重点:初始化处理

在这里插入图片描述

代码实现

int minFallingPathSum(vector<vector<int>>& matrix){int m = matrix.size(), n = matrix[0].size();//状态表示,以[i,j]为结尾,dp[i][j]表示到达[i,j]位置时的下降路径最小和 起点是下标为1的行//学到个新的点,二维数组指定值初始化vector<vector<int>> dp(m + 1, vector<int>(n + 2, INT_MAX));//初始化for (int j = 0; j <= n + 1; j++){dp[0][j] = 0;}//填表for (int i = 1; i <= m; i++){for (int j = 1; j <= n; j++){//状态转移方程dp[i][j] = min(min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i - 1][j + 1]) + matrix[i - 1][j - 1];}}//返回值,从状态表最后一行中找到最小的和int ret = INT_MAX;for (int j = 1; j <= n; j++){ret = min(ret, dp[m][j]);}return ret;
}

6.地下城游戏

题目

在这里插入图片描述

在这里插入图片描述

算法原理

本道题和上面的几道题不同,属于较复杂的路径问题,难点在于转换思想,不再局限于由前状态推出后状态(我当时自己写的就是一直局限于前推后,各种复杂情况需要处理,后来发现反着推会非常简单)。

如果是由前推后,dp[i][j]表示到达[i,j]位置时所需的最小初始血量,以示例一为例,起点位置的健康值为-2,说明初始血量最小需要为3才能通过,但是,如果设置为3,往下移动是-5,或者往右移动是-3,此时的最小初始血量都不能保证通过,所以,最小初始血量不光受当前位置前的状态影响,还受当前位置后的状态影响,所以无法由前状态推出后状态。这时候就需要反向思考。

dp[i][j]表示以下标[i,j]为起点,到达终点时所需的最小初始血量,有后状态推出前状态,填表时就是从最后一行到第一行,其中每一行的顺序是从右向左,题中的起点位置为下标[0,0],所以最后返回的结果是dp[0,0],表示以下标[0,0]为起点,到达重点是所需的最小血量。

假设当前下标为[i,j],从该位置到下一个位置有两种情况,第一种是向右移动到下标[i,j+1]位置(重复子问题,用dp[i][j+1]表示该位置到达终点所需的最小初始血量);第二种是向下移动到下标[i+1,j]位置(重复子问题,用dp[i+1][j]表示该位置到达终点所需的最小初始血量);根据贪心思想,选择两种情况中的最小值,假设当前位置所需的最小初始血量dp[i][j]为x,下一个位置的为y(dp[i][j+1]或者dp[i+1][j]),x+当前位置消耗的血量(dungeon[i][j])需要大于等于y才能到达下一个位置,所以x需要大于等于y减去当前位置消耗的血量(dungeon[i][j]),取最小的就是等于。注意点如果y减去当前位置消耗的血量(dungeon[i][j])小于等于0,说明当前不用消耗血量,而是治疗,但是治疗过量变为负数,说明初始血量最小为1就能通过当前位置。

重点:初始化处理

在这里插入图片描述

代码实现

int calculateMinimumHP(vector<vector<int>>& dungeon){int m = dungeon.size(), n = dungeon[0].size();//状态表示,以[i,j]为起点,dp[i][j]表示到达终点时需要的最小健康值,终点为[m-1,n-1]//由后状态推出前状态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];if(dp[i][j]<=0){dp[i][j] = max(1, dp[i][j]);}}}//返回值return dp[0][0];
}

以上就是关于动态规划中的路径问题讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!

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

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

相关文章

【Linux】深入理解linux权限

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、权限是什么 二、用户和身份角色 三、文件属性 1. 文件属性表示 2. 文件类型 3. 文件的权限属性 四、修改文件的权限属性和角色 1. …

嵌入式linux系统中VIM编辑工具用法与GCC参数详解

大家好,今天主要给大家分享一下,如何使用linux系统中的VIM编辑工具和GCC的参数详解。 第一:安装VIM 命令:sudo apt get install vim 第二:工作模式 普通模式:打开一个文件时的默认模式,按ESC返回普通模式 插入模式:i/o/a进入插入模式,不同在于在光标前后插入 可视…

【前端开发】HTML+CSS+JavaScript前端三剑客的基础知识体系了解

前言 &#x1f31f;&#x1f31f;本期讲解关于HTMLCSSJavaScript的基础知识&#xff0c;小编带领大家简单过一遍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 …

蓝桥杯---数青蛙(leetcode第1419题)

文章目录 1.题目重述2.例子分析3.思路分析4.思路总结5.代码解释 1.题目重述 这个题目算是模拟这个专题里面的一类比较难的题目了&#xff0c;他主要是使用crock这个单词作为一个整体&#xff0c;让我们确定&#xff1a;给你一个字符串&#xff0c;至少需要多少个青蛙进行完成鸣…

WidowX-250s 机械臂学习记录

官网教程&#xff1a;Python Demos — Interbotix X-Series Arms Documentation 系统&#xff1a;Ubuntu20.04&#xff0c;ROS1 相关的硬件编译配置跳过 Python Demos 这些演示展示了使用 Interbotix Python Arm 模块的各种方法&#xff08;点击链接查看完整的代码文档&…

【CubeMX-HAL库】STM32F407—无刷电机学习笔记

目录 简介&#xff1a; 学习资料&#xff1a; 跳转目录&#xff1a; 一、工程创建 二、板载LED 三、用户按键 四、蜂鸣器 1.完整IO控制代码 五、TFT彩屏驱动 六、ADC多通道 1.通道确认 2.CubeMX配置 ①开启对应的ADC通道 ②选择规则组通道 ③开启DMA ④开启ADC…

集成右键的好用软件,支持多线程操作!

今天给大家分享一个超级实用的小工具&#xff0c;真的能帮上大忙呢&#xff01;这个软件是吾爱大神无知灰灰精心制作的&#xff0c;简直就是图片转换界的“小能手”。 它能一键把webp格式的图片转换成png格式&#xff0c;而且速度超快&#xff0c;完全不输那些付费的软件&#…

CSDN 博客之星 2024:肖哥弹架构的社区耕耘总结

#博客之星2024年度总评选—主题文章创作# CSDN 博客之星 2024&#xff1a;肖哥弹架构的社区耕耘总结 肖哥弹架构 是一位专注于技术分享和社区建设的博客作者。今年&#xff0c;我荣幸地再次入选CSDN博客之星TOP300&#xff0c;这不仅是对我过去努力的认可&#xff0c;更是对未…

【分布式理论7】分布式调用之:服务间的(RPC)远程调用

文章目录 一、RPC 调用过程二、RPC 动态代理&#xff1a;屏蔽远程通讯细节1. 动态代理示例2. 如何将动态代理应用于 RPC 三、RPC序列化与协议编码1. RPC 序列化2. RPC 协议编码2.1. 协议编码的作用2.2. RPC 协议消息组成 四、RPC 网络传输1. 网络传输流程2. 关键优化点 一、RPC…

综合评价 | 基于随机变异系数-TOPSIS组合法的综合评价模型(Matlab)

基于随机变异系数-TOPSIS组合法的综合评价模型 代码获取私信回复&#xff1a;综合评价 | 基于随机变异系数-TOPSIS组合法的综合评价模型&#xff08;Matlab&#xff09; 一、引言 1.1、研究背景与意义 在现代社会&#xff0c;随着信息量的不断增加和数据复杂性的提升&#…

采用分步式无线控制架构实现水池液位自动化管理

以下是基于巨控GRM241Q-4D4I4QHE模块的完整技术方案&#xff0c;采用分步式无线控制架构实现水池液位自动化管理&#xff1a; 一、系统架构设计 硬件部署 山顶单元 GRM241Q模块&#xff08;带4G功能&#xff09; 液位计&#xff08;4-20mA&#xff09; 功能&#xff1a;实时采…

Vue设计模式到底多少种?

Vue设计模式到底多少种&#xff1f; 很多同学问&#xff0c;Vue到底有多少种设计模式&#xff1f;&#xff1f;各个模式到底是什么意思&#xff1f;&#xff1f;又各自适合什么场景&#xff1f;&#xff1f; 这里我给大家直接说下&#xff0c;Vue的设计模式没有一个固定的数值…

[LeetCode] day19 454. 四数相加 II

题目链接 题目描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 示例 1&#xff1a; 输入&…

查看二进制程序内的 .interp 段

synopsis 可以使用 readelf &#xff0c;objdump&#xff0c;hexdump等工具查看 二进制程序内的.interp段信息。 1. 使用readelf查看.interp段 readelf 是一个查看ELF&#xff08;Executable and Linkable Format&#xff09;文件信息的工具&#xff0c;特别适合查看ELF头和…

【时时三省】(C语言基础)基础习题1

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 1.什么是程序&#xff1f;什么是程序设计 程序是为实现特定目标或解决特定问题&#xff0c;用计算机能理解和执行的语言编写的一系列指令的集合。 程序设计是问题分析&#xff0c;设计算法…

食品饮料生产瓶颈?富唯智能协作机器人来 “破壁”

在食品和饮料行业的发展进程中&#xff0c;诸多生产瓶颈如重复性劳动负担、复杂环境作业难题、季节性产能波动等&#xff0c;长期制约着企业的高效运营与进一步发展。如今&#xff0c;富唯智能协作机器人的出现&#xff0c;为这些难题提供了完美的解决方案&#xff0c;正逐步改…

[创业之路-289]:《产品开发管理-方法.流程.工具 》-15- 需求管理 - 第1步:原始需求收集

概述&#xff1a; 需求收集是需求管理的第一步&#xff0c;也是产品开发、项目管理或软件设计中的关键步骤。原始需求收集主要是指从各种来源获取关于产品或服务的初步需求和期望。 以下是对需求管理中的原始需求收集的详细分析&#xff1a; 1、原始需求收集的目的 原始需求…

81页精品PPT | 华为流程与信息化实践与架构规划分享

华为流程与信息化实践与架构规划分享主要围绕华为在业务流程与信息化建设方面的经验、企业架构规划方法以及企业数字化转型路径展开。华为通过持续的业务变革和信息化建设&#xff0c;从本土企业逐步发展为国际化、全球化企业&#xff0c;其管理体系以持续创新和世界级管理体系…

DeepSeek 实践总结

目录 1、与AI对话-万能公式 chatbox 谷歌插件方式 命令行方式 2、ChatPPT+DeepSeek形成PPT 1、与AI对话-万能公式 *明确身份+任务+细节描述+输出格式* 这样的方式能更加准确的帮助你快速获得接近你想法的内容。 身份:你是谁?(网络负责人/记者/老师。。。)任务:要解决什…

51c自动驾驶~合集49

我自己的原文哦~ https://blog.51cto.com/whaosoft/13164876 #Ultra-AV 轨迹预测新基准&#xff01;清华开源&#xff1a;统一自动驾驶纵向轨迹数据集 自动驾驶车辆在交通运输领域展现出巨大潜力&#xff0c;而理解其纵向驾驶行为是实现安全高效自动驾驶的关键。现有的开…