基础算法之——【动态规划之路径问题】1

news2025/1/20 10:52:18

今天更新动态规划路径问题1,后续会继续更新其他有关动态规划的问题!动态规划的路径问题,顾名思义,就是和路径相关的问题。当然,我们是从最简单的找路径开始!

  • 动态规划的使用方法:
    1.确定状态并定义状态数组:(i,j)代表什么意思?dp[i][j]又是什么意思?
    2.确定状态转移方程,即递推公式
    3.确定边界条件并初始化
    4.确定遍历顺序
    5.状态转移
    6.输出结果

在这里插入图片描述

文章目录

  • 一、LC 62 不同路径
      • 方法一:深度优先搜索
      • 方法二:动态规划(二维)
      • 方法三:动态规划(一维)
      • 方法四:排列组合
  • 二、LC 63 不同路径II
      • 方法一:动态规划(二维)
      • 方法二:动态规划(一维)
      • 方法三:记忆化搜索
  • 三、LC 64 最小路径和
      • 方法一:动态规划(二维)
      • 方法二:动态规划(一维)


一、LC 62 不同路径

LC 62 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?
在这里插入图片描述


方法一:深度优先搜索

代码如下:

class Solution {
private:
    int dfs(int m,int n,int i,int j){

        //行或列有至少一个越界
        if(i>m||j>n) return 0;

        //到达终点(在竖直方向达到m,水平方向达到n,也即坐标达到(m,n))
        if(i==m && j==n) return 1;

        //递归搜索(左子树和右子树)
        return dfs(m,n,i+1,j)+dfs(m,n,i,j+1);
    }
public:
    int uniquePaths(int m, int n) {
        
        //从根节点开始遍历
        int cnt=dfs(m,n,1,1);
        return cnt;

    }
};

方法二:动态规划(二维)

代码如下:

/*动态规划的使用方法:
1.确定状态并定义状态数组:(i,j)代表什么意思?dp[i][j]又是什么意思?
2.确定状态转移方程,即递推公式
3.确定边界条件并初始化
4.确定遍历顺序
5.状态转移
6.输出结果
*/
class Solution {

public:
    int uniquePaths(int m, int n) {
        //定义一个状态数组,用来存方法数      
        int dp[101][101]={0};

        //初始化状态数组
        for(int i=0;i<m;i++){
            dp[i][0]=1;
        }
        for(int j=0;j<n;j++){
            dp[0][j]=1;
        }

        //遍历
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                //状态转移
                dp[i][j]=dp[i][j-1]+dp[i-1][j];
            }
        }

        //返回结果
        return dp[m-1][n-1];
    }
};

方法三:动态规划(一维)

代码如下:

class Solution {
public:
    int uniquePaths(int m, int n) {
          
        //定义一维状态数组  
        int dp[101]={0};

        //初始化数组值为1,即相对于二维数组第一行全是1
        for(int i=0;i<n;i++){
            dp[i]=1;
        }

        //遍历
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                
                //状态转移:dp[j]指的是上一行的j,dp[j-1]指的是当前行左边的j;
                //每次状态转移都相当于先将上一行的运算拷贝过来,再加上从左面来的方案数
                dp[j]=dp[j-1]+dp[j];
            }
        }

        return dp[n-1];
      
    }
};

方法四:排列组合

代码如下:

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long numerator = 1; // 初始化分子

        int denominator = m - 1; // 初始化分母

        int count = m - 1;//定义分子的乘积项的个数

        int t = m + n - 2;//定义分子的最大乘积项

        while (count--) {//分子累乘count项

            numerator *= (t--);
            while (denominator != 0 && numerator % denominator == 0) {

                //约分(也即除以公因数)
                numerator /= denominator;

                //约去一个公因数
                denominator--;
            }
        }
        return numerator;
    }
};

二、LC 63 不同路径II

LC 63 不同路径II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。
在这里插入图片描述



方法一:动态规划(二维)

代码如下:

 class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {

        //求出二维动态数组的行数
        int m=obstacleGrid.size();

        //求出二维动态数组的列数
        int n=obstacleGrid[0].size();

        //定义状态数组
        int dp[101][101]={0};
        
        //边界判断
        if(obstacleGrid[0][0]==1 || obstacleGrid[m-1][n-1]==1) return 0;

        //初始化状态数组
        dp[0][0]=1;

        //遍历
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                
                //如果是障碍物,则此路不通,路径数归零
                if(obstacleGrid[i][j]==1){
                     dp[i][j]=0;
                     continue;
                }

                //状态转移,此处和上面的一样
               if(i>0 && j>0) dp[i][j]=dp[i-1][j]+dp[i][j-1];
               else if(i>0) dp[i][j]=dp[i-1][j];
               else if(j>0) dp[i][j]=dp[i][j-1];

//也可以这样写
/*
 if(obstacleGrid[i][j]==0){
                      //状态转移,此处和上面的一样
               if(i>0 && j>0) dp[i][j]=dp[i-1][j]+dp[i][j-1];
               else if(i>0) dp[i][j]=dp[i-1][j];
               else if(j>0) dp[i][j]=dp[i][j-1];

                }
              
            }
            else continue;
*/
            }
        }
        return dp[m-1][n-1];

    }
};

方法二:动态规划(一维)

代码如下:

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if (obstacleGrid[0][0] == 1)
            return 0;
        vector<int> dp(obstacleGrid[0].size(),0);
        
        //初始化一维状态数组(第一行)
        for (int j = 0; j < dp.size() && obstacleGrid[0][j] == 0 ; ++j)
            if (j == 0)
                dp[j] = 1;
            else
                dp[j] = dp[j-1];

        //
        for (int i = 1; i < obstacleGrid.size(); ++i)//行
            for (int j = 0; j < dp.size(); ++j){//列

                if (obstacleGrid[i][j] == 1)
                    dp[j] = 0;

                else if (j != 0)
                    dp[j] = dp[j] + dp[j-1];
            }
        return dp.back();//返回最后一个状态对应值
    }
};

方法三:记忆化搜索

代码如下:

class Solution {
public:
    int m,n;
    vector<vector<int>>memo;
    vector<pair<int,int>>dir{{0,1},{1,0}};
    int uniquePathsWithObstacles(vector<vector<int>>& ob) {
            n=ob.size();
            m=ob[0].size();
            if(ob[0][0]==1||ob[n-1][m-1]==1){
                return 0;
            }
            memo.resize(n,vector<int>(m,0));
            return dfs(ob,0,0);
    }
    int dfs(vector<vector<int>>&ob,int i,int j){
        if(memo[i][j]!=0){
            return memo[i][j];
        }
        if(i==n-1&&j==m-1){
            memo[i][j]=1;
            return 1;
        }
        int cur=0;
        for(auto &d:dir){
            int x=i+d.first;
            int y=j+d.second;
            if(x>=0&&x<n&&y>=0&&y<m&&ob[x][y]==0){
                cur+=dfs(ob,x,y);
            }
        }
        memo[i][j]=cur;
        return memo[i][j];
    }
};

作者:Gallant MurdockrFZ
链接:https://leetcode.cn/problems/unique-paths-ii/solutions/2466610/dfsji-yi-hua-sou-suo-by-gallant-murdockr-e882/
来源:力扣(LeetCode)


三、LC 64 最小路径和

LC 64 最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。
在这里插入图片描述


方法一:动态规划(二维)

代码如下:

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {

        //定义一个二维状态数组
        int dp[201][201]={0};

        //初始化状态数组
        dp[0][0]=grid[0][0];

        //获得行数和列数
        int m=grid.size();
        int n=grid[0].size();

        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){

                //正常情况
                if(i>0 && j>0){
                    dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
                }

                //边界条件
                else if(i>0) dp[i][j]=dp[i-1][j]+grid[i][j];
                else if(j>0) dp[i][j]=dp[i][j-1]+grid[i][j];

            }
        }
        return dp[m-1][n-1];

    }
};

方法二:动态规划(一维)

代码如下:

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {

        //获取行数和列数
       int m=grid.size();
       int n=grid[0].size();

        //定义一维状态数组
       int dp[201]={0};

       //初始化第一行
       dp[0]=grid[0][0];
       for(int i=1;i<n;i++){
           dp[i]=grid[0][i]+dp[i-1];
       }

        //状态转移(配合滚动数组优化)
       for(int i=1;i<m;i++){
           for(int j=0;j<n;j++){
               //左边界
               if(j==0) dp[j]+=grid[i][j];

               //其他情况
               else dp[j]=min(dp[j-1],dp[j])+grid[i][j];
           }
       }
       return dp[n-1];

    }
};

我以前没怎么接触过动态规划,目前就是每天有空看看题,想想解题思路啥的,但愿有效果吧!
在这里插入图片描述

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

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

相关文章

《视觉 SLAM 十四讲》V2 第 6 讲 非线性优化 【高斯牛顿法、列文伯格-马夸尔特方法 、Ceres 库 和 g2o库 】

文章目录 6.1.2 最小二乘 寻找下降增量 Δ x k \Delta\bm{x}_k Δxk​的 4 种方法6.2.1 一阶和二阶梯度法(最速下降法、牛顿法)6.2.2 高斯牛顿法6.2.3 列文伯格-马夸尔特方法 【阻尼牛顿法】【信赖区域法】 6.3 实践6.3.1 手写高斯牛顿法 【Code】6.3.2 谷歌的优化库 Ceres 【最…

自动驾驶学习笔记(一)——Apollo平台

#Apollo开发者社区# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 Apollo框架 开发平台 总结 前…

【TMS320F28374之PWM】

简介 增强型脉宽调制器(ePWM)外设是控制商业和工业设备中许多电力电子系统的关键元件。这些系统包括数字电机控制、开关模式电源控制、不间断电源(UPS)和其他形式的电源转换。ePWM外设还可以执行数模转换(DAC)功能&#xff0c;其中占空比相当于DAC模拟值;它有时被称为电源DAC。…

[机缘参悟-109] :接纳生活中的无完美是一种修行,过度追求完美是一种“我执”,接纳污秽、肮脏、邪恶、小人是一种高度

目录 前言&#xff1a; 一、天地以万物为刍狗&#xff0c;站在大自然的视角没有善恶 1.1 天地以万物为刍狗&#xff0c;在自然面前&#xff0c;一切生命都平等 1.2 食物链是一个闭环系统&#xff0c;无所谓善恶 1.3 在大自然中&#xff0c;人类眼中的“美丽”都诞生于“污…

Python(八十八)函数的参数传递

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

C++设计模式-单件(Singleton)

目录 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-单件&#xff08;Singleton&#xff09; 一、意图 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 二、适用性 当类只能有一…

RK3588开发笔记(一):基于方案商提供的宿主机交叉编译Qt5.12.10

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/133618273 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

最强中间件!Kafka快速入门(Kafka理论+SpringBoot集成Kafka实践)

自媒体文章上下架 需求分析 媒体端下架文章同时app端也下架文章的实现可以通过feign去调用&#xff0c;但这种实现耦合度太高&#xff0c;这里使用MQ进行解耦 自媒体端一旦上下架文章就发送消息给MQ&#xff0c;文章微服务在去读取消息根据消息内容上下架文章 MQ还可以流量削…

SSM - Springboot - MyBatis-Plus 全栈体系(二十二)

第四章 SpringMVC 五、SpringMVC 其他扩展 1. 全局异常处理机制 1.1 异常处理两种方式 开发过程中是不可避免地会出现各种异常情况的&#xff0c;例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题&#xff0c;甚至直接导致程序崩溃。…

嵌入式学习笔记(47)Nand的常见操作及流程分析

9.3.1坏块检查 (1)Flash使用之前一定要先统一擦除&#xff08;擦除的单元是块&#xff09;。Flash类设备擦除后里边全是1&#xff0c;所以擦干净之后读出来的值是0xFF (2)检查坏块的思路就是&#xff1a;先擦除&#xff0c;然后将整个块读出来&#xff0c;依次检测各字节是否…

【Java项目推荐之黑马头条】CSDN中的定时发布知道吧,你项目中的定时发布是如何实现的?

延迟队列精准发布文章 文章定时发布 延迟任务概述 什么是延迟任务 定时任务&#xff1a;有固定周期的&#xff0c;有明确的触发时间延迟队列&#xff1a;没有固定的开始时间&#xff0c;它常常是由一个事件触发的&#xff0c;而在这个事件触发之后的一段时间内触发另一个事…

起号1个月后,我分析了一些AI数字人项目的红利期和优缺点

本期是赤辰第33期AI项目教程&#xff0c;底部准备了9月粉丝福利&#xff0c;可以免费领取。hi&#xff0c;同学们&#xff0c;AI的应用在各场景都已经呈井喷态势&#xff0c;好比就连近期的杭州亚运会开幕式都采用了数字人火炬手&#xff0c;AI技术的发展不断刷新着我们的脑洞上…

数据科学家的编程语言

数据科学家的编程语言 在今天有256种编程语言可供选择&#xff0c;选择要学习的语言可能会令人不知所措和困难。有些语言更适用于构建游戏&#xff0c;而有些更适用于软件工程&#xff0c;还有一些更适用于数据科学。 编程语言的类型 低级编程语言是计算机用来执行操作的最容…

Spring-事务管理-加强

目录 开启事务 编程式事务 声明式事务 声明式事务的优点 声明式事务的粒度问题 声明式事务用不对容易失效 Spring事务失效可能是哪些原因 Transactional(rollbackFor Exception.class)注解 Spring 事务的实现原理 事务传播机制 介绍 用法 rollbackFor 场景举例 …

Python爬取wallhaven的所有4k壁纸图片

目录 一、前端结构 二、代码 一、前端结构 为get请求&#xff0c;携带参数如下: 随page参数变化网页变化 需要在整张页面中进入: //section[class"thumb-listing-page"]//li/figure/a/href 进入后获取图片src: //section[class"fit"]/div[class"s…

Hadoop伪分布式环境搭建

什么是Hadoop伪分布式集群&#xff1f; Hadoop 伪分布式集群是一种在单个节点上模拟分布式环境的配置&#xff0c;用于学习、开发和测试 Hadoop 的功能和特性。它提供了一个简化的方式来体验和熟悉 Hadoop 的各个组件&#xff0c;而无需配置和管理一个真正的多节点集群。 在 Ha…

国庆作业 day 1

服务器 #include<myhead.h>//消息结构体 typedef struct {long msgtype; //消息类型char data[1024]; //消息正文 }Msg_ds;#define SIZE sizeof(Msg_ds)-sizeof(long) //正文大小 int main(int argc, const char *argv[]) {//1、创建key值key_t key;…

Spring 作用域解析器AnnotationScopeMetadataResolver

博主介绍&#xff1a;✌全网粉丝近5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经…

Java项目防止SQL注入的几种方案

目录 一、什么是SQL注入&#xff1f; 二、Java项目防止SQL注入方式 1、PreparedStatement防止SQL注入 2、mybatis中#{}防止SQL注入 3、对请求参数的敏感词汇进行过滤 4、nginx反向代理防止SQL注入 一、什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数…

Latent Diffusion Models 论文解读

论文下载地址&#xff1a;https://arxiv.org/pdf/2112.10752.pdf 0 摘要 通过将图像形成过程分解为去噪自编码器的连续应用&#xff0c;扩散模型&#xff08;DM&#xff09;在图像数据及其他方面取得了最先进的合成结果。此外&#xff0c;它们的表述允许一种指导机制来控制图…