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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux----> tail、cat、more、head、less的用法详解

1.tail命令&#xff1a;用于查看文件的最后几行内容。 基本用法&#xff1a;tail [选项] [文件] 常用选项&#xff1a; -n <行数>&#xff1a;显示最后的 <行数> 行。-f&#xff1a;实时显示文件新增内容&#xff0c;通常用于查看日志文件。 示例&#xff1a;…

算法金 | 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost 算法大全

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 决策树是一种简单直观的机器学习算法&#xff0c;它广泛应用于分类和回归问题中。它的核心思想是将复杂的决策过程分解成一系列简单的决…

JavaSE-面向对象(总结复习详细)

前言: 在 Java SE 中&#xff0c;面向对象编程是一种基本的编程范式&#xff0c;它将现实世界中的问题抽象成对象&#xff0c;然后通过对象之间的交互来解决问题。在面向对象编程中&#xff0c;所有的操作都是围绕对象展开的&#xff0c;对象拥有属性和行为&#xff0c;并且可…

MambaMixer:突破Transformers限制的高效深度学习架构

深度学习模型尤其是Transformers架构&#xff0c;已经在诸如自然语言处理、计算机视觉和时间序列预测等多个领域取得了显著成就。然而&#xff0c;随着模型输入序列长度的增加&#xff0c;传统的Transformers模型面临着显著的扩展性问题。其核心问题在于&#xff0c;Transforme…

GPT-5:编织未来智能的经纬

GPT-5技术突破预测 随着GPT-5的预告&#xff0c;人工智能的叙事正步入一个崭新的篇章。想象中的GPT-5不仅是自然语言处理&#xff08;NLP&#xff09;领域的革命&#xff0c;更是对“理解”本身的一次重新定义。它可能集成深度学习的最新进展&#xff0c;如自注意力机制的进一步…

Java访问修饰符的区别

public&#xff1a;公开的&#xff0c;任何地方都可以访问。 protected&#xff1a;受保护的&#xff0c;同一个包中的类和所有子类(可跨包)可以访问。 private&#xff1a;私有的&#xff0c;只有在同一个类中可以访问。 默认&#xff08;无修饰符&#xff09;&#xff1a;包级…

SmartEDA革新来袭:融合Multisim与Proteus精髓,引领电子设计新纪元!

在电子设计领域&#xff0c;每一次技术的革新都如同春风化雨&#xff0c;滋润着设计师们的心田。今天&#xff0c;我们迎来了一个划时代的电子设计自动化&#xff08;EDA&#xff09;工具——SmartEDA&#xff0c;它不仅融合了业界知名的Multisim和Proteus的精华&#xff0c;更…

【计算机毕业设计】077停车场微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

FreeRTOS移植到STM32

一、找一个STM32的裸机工程模板 我们以STM32F103裸机程序为例 随便找的一个裸机程序 二、去官网上下载FreeRTOS V9.0.0 源码 在移植之前&#xff0c;我们首先要获取到 FreeRTOS 的官方的源码包。这里我们提供两个下载 链 接 &#xff0c; 一 个 是 官 网 &#xff1a; http:…

若依 ruoyi 分离版 vue 简单的行内编辑实现

需要实现的效果&#xff1a;双击文本 - 修改文本 - 保存修改。 原码&#xff1a;仅文本显示文字内容 <el-table-column label"商品" align"center" prop"goodsName" width"200" v-if"columns[1].visible" /> 实现…

基于Vue,mysql,JavaEE的简单投票与投票管理系统

项目介绍 ​ 本项目&#xff0c;基于Vue2.6,mysql,JavaEE 实现简单的投票与投票管理系统 项目地址 VotingSystem: 投票系统1.0 管理员和普通用户 (gitee.com) 有问题请评论私聊哦 项目分类 数据库 创建投票人&#xff0c;被投票人&#xff0c;投票关系&#xff08;追踪谁…

基于Java的蛋糕预定系统【附源码+LW】

摘 要 当今社会进入了科技进步、经济社会快速发展的新时代。国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统购物方式采取了人工的管理方法&#xff0c;但这种管理方法存…

使用 nvm 管理 Node 版本及 pnpm 安装

文章目录 GithubWindows 环境Mac/Linux 使用脚本进行安装或更新Mac/Linux 环境变量nvm 常用命令npm 常用命令npm 安装 pnpmNode 历史版本 Github https://github.com/nvm-sh/nvm Windows 环境 https://nvm.uihtm.com/nvm.html Mac/Linux 使用脚本进行安装或更新 curl -o- …

阿里云服务器数据库迁云: 数据从传统到云端的安全之旅(WordPress个人博客实战教学)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 一、 开始实战1.2创建实验资源1.3重置云服务器ECS的登录密码&#xff08;请记住密码&#xff09;1.4 设置安全组端口1…

武汉星起航:跨境热销新趋势,亚马逊美国站与欧洲站选品大赏

亚马逊作为全球领先的电商平台&#xff0c;其美国站和欧洲站一直是全球卖家争相入驻的热门站点。这两个站点不仅拥有庞大的消费群体和完善的物流体系&#xff0c;更以其独特的选品策略吸引了众多消费者的目光。武汉星起航将深入剖析亚马逊美国站和欧洲站当前热销的选品&#xf…

【Qt】之【Bug】大量出现“未定义的标识符”问题

背景 构建时出现大量错误 原因 中文注释问题 解决 方法1. 报错代码附近的中文注释全部删掉。。。 方法2. 报错的文件添加 // Chinese word comment solution #pragma execution_character_set("utf-8")

爱奇艺 Opal 机器学习平台:特征中心建设实践

01 综述 Opal 是爱奇艺大数据团队研发的一站式机器学习平台&#xff0c;旨在提升特征迭代、模型训练效率&#xff0c;帮助业务提高收益。整个平台覆盖了机器学习生命周期中特征生产、样本构建、模型探索、模型训练、模型部署等在内的多个关键环节。其中特征作为模型训练的基石…

ZYNQ MPSOC浅说

1 MPSOC PL端 Zynq UltraScale MPSoC PL 部分等价于 FPGA。简化的 FPGA 基本结构由 6 部分组成&#xff0c;分别为可编程输入/输出单元、基本可编程逻辑单元、嵌入式块RAM、丰富的布线资源、底层嵌入功能单元和内嵌专用硬核等。 2 MPSOC PS端 MPSoC 实际上是一个以处理器为…

Quartz定时任务组件

官网&#xff1a;http://www.quartz-scheduler.org/ 1&#xff09;job - 任务 - 你要做什么事&#xff1f; 2&#xff09;Trigger - 触发器 - 做什么事&#xff0c;什么时候触发&#xff0c;可以传入任务 3&#xff09;Scheduler - 任务调度 - 可以传入多个触发器进行任务调…

软件测试之接口测试(Postman/Jmeter)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是接口测试 通常做的接口测试指的是系统对外的接口&#xff0c;比如你需要从别的系统来…