DP:解决路径问题

文章目录

  • 二维DP模型
  • 如何解决路径问题
  • 有关路径问题的几个问题
    • 1.不同路径
    • 2.不同路径Ⅱ
    • 3.下降路径最小和
    • 4.珠宝的最高价值
    • 5.地下城游戏
  • 总结

在这里插入图片描述

二维DP模型

二维动态规划(DP)模型是一种通过引入两个维度的状态和转移方程来解决复杂问题的技术。它在许多优化和组合问题中广泛应用,尤其是那些需要考虑二维数组或矩阵的情况。

以下是二维DP模型的核心概念和步骤:

  1. 状态定义:二维DP模型使用一个二维数组(或矩阵)来表示问题的状态。每个状态通常由两个变量(例如i和j)表示,表示在问题空间中的某个位置或状态。

  2. 状态转移方程:这是DP的核心。它描述了如何从一个状态转移到另一个状态,通常是通过递推关系来实现。转移方程基于问题的具体特性进行设计。

  3. 初始状态和边界条件:在DP表格中需要明确初始状态和边界条件。这些条件为DP表格的填充提供了起点。

  4. 目标状态:最后,我们通过目标状态来得到问题的最终解。通常是二维数组中的一个或几个特定位置。

如何解决路径问题

路径问题是动态规划中非常经典的一类问题,通常涉及从一个起点到一个终点的最短路径、最大路径或独特路径数等。解决路径问题的常用方法包括递归、回溯和动态规划(DP)。其中,动态规划由于其效率和易理解性,成为解决路径问题的常用技术。以下是解决路径问题的一些常见步骤和示例:

一般步骤

  1. 定义状态:确定DP数组的含义,通常是定义dp[i][j]表示从起点到位置(i, j)的某种路径属性(如路径和、路径数等)。

  2. 状态转移方程:建立递推关系,描述如何从一个状态转移到另一个状态。

  3. 初始化:根据问题的具体情况,设置DP数组的初始值。

  4. 计算DP数组:按照状态转移方程填充DP数组。

  5. 提取结果:通过DP数组得到最终结果。

有关路径问题的几个问题

1.不同路径

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题是一个很典型的二维DP问题,也是二维DP中的路径问题的一种,这道题给定一个宽是m,长是n,让我们求在这个二位数组中从[0,0]点到[m-1,n-1]的方法有多少种。
在这里插入图片描述

算法原理:
算法原理也和传统的DP问题的步骤是一样的。
第一步:状态表示,先确定dp表是初始位置还是 末位置,很显然这道题要我们求的是方法有多少种,dp肯定是末位置,所以这里dp[i][j]到达[i,j]位置时有多少种方法。
第二步:状态转移方程,这道题dp表示的是到达某位置时的方法的种数,
在这里插入图片描述
很显然这道题题目要求只能向下或者向右移动,所以我们只有可能从[i,j]位置的上方或者[i,j]的左方到达[i,j]位置,所以我们需要求[i,j]位置的最多的方法数,只需要求出左边和上面的方法总数之和即可。
状态转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1]
第三步:初始化问题,这道题的当前数据需要用到左边的数据和上面的数据,所以这道题越界的地方应该是红色的地方:在这里插入图片描述
处理这种越界情况我们初始化只需要多开辟一行一列数组:
在这里插入图片描述
这样就不会出现越界的情况了,初始化应该把蓝色的部分全部初始化掉,具体初始哈为多少了,首先这相当于是一个虚拟的节点,为了防止越界而产生的,所以先初始化为0,但是如果初始化为零那么总的方法数就是零了,所以我们需要把[0,1]位置或者[1,0]位置初始化为1.
第四步:填表顺序,这道题很显然是从左上角开始 按顺序遍历。
第五步:返回值问题,这道题求的是到达左下角的方法总数,所以是返回dp[m][n]。

代码展示:

class Solution {
public:int uniquePaths(int m, int n) {//创建一个dp表,第一排和第一列表示虚拟节点vector<vector<int>> dp(m+1,vector<int>(n+1,0));//初始化[0,1]节点dp[0][1]=1;//填表for(int i=1;i<m+1;i++){for(int j=1;j<n+1;j++){//状态转移方程dp[i][j]=dp[i-1][j]+dp[i][j-1];}}//返回值return dp[m][n];}
};

运行结果:
在这里插入图片描述

2.不同路径Ⅱ

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

算法原理:
这道题和上一道题其实是一样的,只需要加一个判断,如果obstacleGrid数组中的值是1的话当前方法数就是0,所以在上道题的条件下加一个if条件的判断即可 。
代码展示:

class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m=obstacleGrid.size();int n=obstacleGrid[0].size();vector<vector<int>> dp(m+1,vector<int>(n+1,0));dp[0][1]=1;for(int i=1;i<m+1;i++){for(int j=1;j<n+1;j++){if(obstacleGrid[i-1][j-1]==0){dp[i][j]=dp[i-1][j]+dp[i][j-1];}}}return dp[m][n];}
};

运行结果:
在这里插入图片描述

3.下降路径最小和

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题的题意很简单,我们首先可以在一个n*n的矩阵的第一行 选三个数
在这里插入图片描述
当我们选中间的格子时,可以下降的格子,我们假设当前格子的下标是[i,j],则可以访问的下一行的下降的格子应该是:[i+1,j-1] [i+1,j] [i+1,j+1]这三个下标,这道题让 我们求的就是到达最后一行的时候下降的最小的路径和,每个方格中的值就表示当前格子的路径数,所以当到达最后一行的时候走过的路径和就是走过的所有格子的值的和。
算法原理:
第一步:状态表示,这道题根据问题我们就知道这道题求的是下降路径最小和,所以我们的dp[i][j]表示的是到达[i][j]位置的时候的当前最小和。
第二步:状态转移方程,我们假设一个格子的下标是[i,j]。
在这里插入图片描述

[i,j]的最小下降路径是不是应该等于上面三个的相邻的格子的最小路径加上当前格子的值。
所以状态转移方程应该是:dp[i][j]=min(dp[i-1][j],dp[i-1][j-1],dp[i-1][j+1])+matrix[i][j]
第三步:初始化为题,其实初始化还是和上面的一样,但是因为我们要用到上一行左边和右边的格子,所以这里会出现越界的格子不止左边和上面的格子还有右边的格子
在这里插入图片描述
所以我们开辟空间应该这样开辟:
在这里插入图片描述
初始化应该初始化蓝色格子,由于当我们请求[i,j-1]位置的最小路径和的时候最左边的一列会影响最小值的大小,,所以这里初始化不能初始化为零,应该初始化为正无穷(INT_MAX)右边的蓝色格子也 应该初始化为正无穷,但是上面一排的格子应该初始化为0,这样才不会影响结果。
第四步:填表顺序,填表 顺序按顺序遍历。
第五步 :返回值,由于这道题求的是最小路径和,所以应该返回dp数组中最后一行中的最小值。
代码展示:

class Solution {
public:int minFallingPathSum(vector<vector<int>>& matrix) {int m=matrix.size();int n=matrix[0].size();vector<vector<int>> dp(m+1,vector<int>(n+2,INT_MAX));for(int j=0;j<n+2;j++){dp[0][j]=0;}for(int i=1;i<m+1;i++){for(int j=1;j<n+1;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 Min=INT_MAX;for(int j=0;j<n+2;j++){Min=min(Min,dp[m][j]);}return Min;}
};

运行结果:
在这里插入图片描述

4.珠宝的最高价值

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题让我们求出珠宝的最高价值,
在这里插入图片描述
很显然根据示例一种的例子,价值最高的珠宝应该是这条路线之和,然后返回
算法原理:
状态表示:dp[i][j]当前位置的珠宝的最高价值。
状态转移方程:max(dp[i-1][j]+frame[i-1][j-1],dp[i][j-1]+frame[i-1][j-1])
初始化:初始化 应该初始化最左边和最上面,初始化为零,因为当前的礼物价值是0.
代码展示:

class Solution {
public:int jewelleryValue(vector<vector<int>>& frame) {int m=frame.size();int n=frame[0].size();vector<vector<int>> dp(m+1,vector<int>(n+1,0));for(int i=1;i<m+1;i++){for(int j=1;j<n+1;j++){dp[i][j]=max(dp[i-1][j]+frame[i-1][j-1],dp[i][j-1]+frame[i-1][j-1]);}}return dp[m][n];}
};

运行结果:
在这里插入图片描述

5.地下城游戏

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题让我们求出就出公主需要的最小健康值,当我们找到最小的一个路径的和加上1就是需要的最小的健康值。
算法原理:
状态表示:dp[i][j]表示当前位置救出公主需要的最小的健康程度,所以这道题的dp[i][j]应该是起点,而不是终点。
状态转移方程:我们设当前位置的最小的健康程度是dp[i][j],则当我们用dp[i][j]-dungeon[i][j]>=dp[i+1][j],同理还有一种情况:dp[i][j]-dungeon[i][j]>=dp[i][j+1]所以最小的健康程度应该是求一个最小值,则状态转移方程:dp[i][j]=min(dp[i+1][j],dp[i][j+1])-dungeon[i][j],但是需要注意的是如果dungeon是一个很大的正值的时候,会出现负数,由于这道题的题目要求是最低的健康值是1,到0或者小于零就死了,所以这道题不能出现负数,所以应该和1取一下max。
初始化,初始化我们和以前不一样,应该:
在这里插入图片描述
应该初始化左下角,由于取的最小值,所以不能初始化为0,应该初始化为INT_MAX,但是公主下面的和右边的格子应该初始化为1,因为救完公主的最小健康值是1,所以应该初始化为1.
填表顺序:从右下角倒着填表
返回值:返回dp数组的第一个值。
代码展示:

class Solution {
public:int calculateMinimumHP(vector<vector<int>>& dungeon) {int m=dungeon.size();int n=dungeon[0].size();vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));dp[m][n-1]=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]=min(dp[i+1][j],dp[i][j+1])-dungeon[i][j];dp[i][j]=max(dp[i][j],1);}}return dp[0][0];}
};

运行结果:
在这里插入图片描述

总结

在这篇博客中,我们详细探讨了动态规划(DP)在解决路径问题中的应用。我们首先回顾了动态规划的基本概念和其核心思想,即通过将问题分解为更小的子问题并存储其结果来避免重复计算。然后,我们通过多个经典的路径问题示例,如最短路径问题、最长路径问题和独特路径问题,展示了如何将动态规划技术应用于实际问题中。

通过这些示例,我们可以看到,动态规划不仅提高了算法的效率,还提供了一种系统化的思维方式,使我们能够更加清晰地理解和解决复杂的路径问题。掌握动态规划技巧,不仅有助于我们在学术研究中取得突破,还能在实际工程项目中大幅度提高解决问题的能力。

希望通过这篇博客,读者们能够更好地理解动态规划的基本原理和应用场景,并在未来的学习和工作中灵活运用这一强大的工具。感谢阅读,如果您有任何问题或建议,欢迎在评论区与我交流。

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

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

相关文章

docker容器内为什么能解析宿主机的hosts文件

Docker容器可以通过特定的网络设置来解析宿主机的hosts文件&#xff0c;这是因为Docker容器在创建网络时&#xff0c;会自动将宿主机的DNS配置信息传递给容器。 当你启动一个Docker容器时&#xff0c;如果没有指定任何DNS相关的选项&#xff0c;Docker默认会使用宿主机的DNS配…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS MessageQueue

CMSIS 2.0接口中的消息&#xff08;Message&#xff09;功能主要涉及到实时操作系统&#xff08;RTOS&#xff09;中的线程间通信。在CMSIS 2.0标准中&#xff0c;消息通常是通过消息队列&#xff08;MessageQueue&#xff09;来进行处理的&#xff0c;以实现不同线程之间的信息…

JS逆向:由 words 、sigBytes 引发的一系列思考与实践

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 在做JS逆向时&#xff0c;你是否经常看到 words 和 sigBytes 这两个属性呢&#xff0c;比如&#xff…

【机器学习300问】135、决策树算法ID3的局限性在哪儿?C4.5算法做出了怎样的改进?

ID3算法是一种用于创建决策树的机器学习算法&#xff0c;该算法基于信息论中的信息增益概念来选择最优属性进行划分。信息增益是原始数据集熵与划分后数据集熵的差值&#xff0c;熵越小表示数据集的纯度越高。有关ID3算法的详细步骤和算法公式在我之前的文章中谈到&#xff0c;…

探索 Electron:将 Web 技术带入桌面应用

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

关于Java依赖版本升级的相关问题解决(持续更新)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

VMware Workstation 安装 Centos 虚拟机

1. 下载 VMware Workstation 直接上网找官网下载即可 2. 下载 Centos 镜像 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 3.打开 VMware 创建虚拟机 3.1点击创建虚拟机 3.2 选择自定义安装 3.3 选择使用 Workstation 的版本 版本越高兼容性越低但性能越好&#xff0c;一…

Linux磁盘分区方案

如下&#xff1a; /boot 分区&#xff1a;存放Linux系统启动有关程序&#xff0c;建议大小100MB。 /usr 分区&#xff1a;存放Linux系统中的应用程序&#xff0c;数据较多&#xff0c;建议大于3GB。 /var 分区&#xff1a;存放Linux系统中经常变化的数据及日志文件&#xff0c…

智慧校园-实训管理系统总体概述

智慧校园实训管理系统&#xff0c;专为满足高等教育与职业教育的特定需求而设计&#xff0c;它代表了实训课程管理领域的一次数字化飞跃。此系统旨在通过革新实训的组织结构、执行流程及评估标准&#xff0c;来增强学生的实践操作技能和教师的授课效率&#xff0c;为社会输送具…

Leetcode 701:二叉搜索树的插入操作

给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 //遍历二叉搜索树&#xff0c;遇到空结点&#…

python如何把一个函数的返回值,当成这个函数的参数值

python如何把一个函数的返回值&#xff0c;当成这个函数的参数值 1. 递归调用 递归是一种函数自己调用自己的方法。在递归调用中&#xff0c;你可以将前一次调用的返回值作为下一次调用的参数。 def recursive_function(x):# 函数逻辑if 条件满足:return 结果else:return rec…

用mn查看单例模式符号表——动态加载的动态链接库中的单例

nm - display name list(symbol table) 问题 有一个疑问由来已久&#xff0c;单例分单线程安全&#xff0c;多线程安全。那么如果动态加载链接库&#xff0c;单例还能保证只存在唯一实例吗&#xff1f; 于是&#xff0c;打算写代码验证一下 验证 1. 代码准备 总共有三个文…

数据结构-分析期末选择题考点(图)

我是梦中传彩笔 欲书花叶寄朝云 目录 图的常见考点&#xff08;一&#xff09;图的概念题 图的常见考点&#xff08;二&#xff09;图的邻接矩阵、邻接表 图的常见考点&#xff08;三&#xff09;拓扑排序 图的常见考点&#xff08;四&#xff09;关键路径 图的常见考点&#x…

c语言实现贪吃蛇小游戏

源码 /** * FileName: snakec* Author:PowerKing * Version&#xff1a;V1.0* Date:2024.6.28* Description: 贪吃蛇小游戏*/#include <curses.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h>/*贪吃蛇游戏 */#define UP 1…

c++ 递归

递归函数是指在函数定义中调用自身的函数。C语言也支持递归函数。 下面是一个使用递归函数计算阶乘的例子&#xff1a; #include <iostream> using namespace std;int factorial(int n) {// 基本情况&#xff0c;当 n 等于 0 或 1 时&#xff0c;阶乘为 1if (n 0 || n…

S32K3 工具篇2:如何在S32DS中使用Segger JLINK下载

S32K3 工具篇2&#xff1a;如何在S32DS中使用Segger JLINK下载 一&#xff0c; S32DS中JLINK下载1.1 Segger JLINK 驱动1.2 S32DS JLINK驱动路径配置1.3 S32DS JLINK debug configuration1.4 S32DS JLINK debug S32K3板子结果 二&#xff0c; JLINK驱动实现S32K344代码下载2.1 …

mysql数据库备份-使用自带工具mysqldump备份工具,mysqlimport/source导入工具

MysqlLimport介绍 MySCLimport是MysQL数据库中的一个命令行工具&#xff0c;用于将数据从外部文件导入MySQL数据库中的表中。它可以导入多种格式的数据&#xff0c;包括CSV、TXT、XML和SQL文件等。本文将介绍MySQLimport的用法&#xff0c;并通过代码示例演示如何使用它来导入…

高考落幕,暑期西北行,甘肃美食等你来尝

高考结束&#xff0c;暑期来临&#xff0c;西北之旅成为许多人的热门选择。而来到甘肃&#xff0c;除了领略壮丽的自然风光和深厚的历史文化&#xff0c;甘肃特产和传统面点以其独特的风味和传统的制作工艺也为游客们带来了一场地道的甘肃美食体验。 平凉的美食&#x…

c++ try 函数

在C中&#xff0c;try函数用于捕获和处理异常。以下是一个演示try函数的示例&#xff1a; #include <iostream> #include <stdexcept>double division(int x, int y) {if (y 0) {throw std::runtime_error("Divide by zero error");}return x / y; }in…

005-GeoGebra基础篇-GeoGebra的点

新手刚开始操作GeoGebra的时候一般都会恨之入骨&#xff0c;因为有些操作不进行学习确实有些难以凭自己发现。 目录 一、点的基本操作1. 通过工具界面添加点2. 关于点的选择&#xff08;对象选择通用方法&#xff09;&#xff08;1&#xff09;选择工具法&#xff08;2&#xf…