动态规划之路径问题

路径问题

  • 1. 不同路径(medium)
  • 2. 不同路径II(medium)
  • 3. 礼物最大值(medium)
  • 4. 下降路径最小和(medium)
  • 5. 最⼩路径和(medium)
  • 6. 地下城游戏(hard)

1. 不同路径(medium)

1.题目链接:不同路径
2.题目描述:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
在这里插入图片描述

3.问题分析:
对于动态规划关于路径问题的分析,首先需要选取某个位置,然后以该位置为起点或者结尾进行分析。如这题dp数组中i位置的结果是需要i-1、i-2等位置算出来的,这种情况就以i位置为结尾进行分析。

  1. 状态表示:对于m*n的网格来说,每一个格子可以对应到一个二维数组中的元素,对于从起点到某点(i,j)由多少种不同路径是从起始位置进行计算,所以以(i,j)位置为结尾进行分析。用dp[i][j]表示:从起点位置到[i,j]位置处,一共有多少种方式。有时候是不知道状态表示是正确还是错误的,为此只能先往下分析
  2. 状态转移方程:对(i,j)位置进行分析,dp[i][j]表示从起点位置到[i , j]位置处,一共有多少种方式,那么怎样才能到达 [i , j] 这个位置?因为只能往下或者往右走,所以到达 [i , j] 位置可以是 [i - 1, j] 或者是 [i , j - 1]这两个位置,两个位置的值进行相加 ,就是到达[i , j]位置处总共的方式。因此状态转移方程为:dp[i , j] = dp[i - 1, j] + [i , j - 1]。
  3. 初始化:对于第一行第一列来说,进行-1操作会放生越界情况。可以用if语句判断一下,也可以添加一行一列,多出来的一行一列成为辅助节点,使⽤这种技巧要注意两个点:辅助结点⾥⾯的值要保证后续填表是正确的;下标的映射关系。初始化只将dp[0][1]位置初始化为1即可。
  4. 填表顺序:从上往下填每⼀⾏,在填写每⼀⾏的时候从左往右。
  5. 返回值:返回dp[m][n]。
    在这里插入图片描述

4.代码如下:

class Solution
{
public:
    int uniquePaths(int m, int n)
    {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // 创建⼀个 dp表
        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. 不同路径II(medium)

1.题目链接:不同路径II
2.题目描述
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

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

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
在这里插入图片描述

3.问题分析
这道题和不同路径I区别就是这道题中的网格有障碍物,所以大致分析思路是相同的,就比如这道题是以[i, j]位置为结尾进行分析,状态表示也相同。

  1. 状态表示:dp[i][j] 表示:⾛到 [i, j] 位置处,⼀共有多少种⽅式。
    以[i, j]位置为结尾进行分析,同上到题,到达 [i , j] 位置可以是 [i - 1, j] 或者是 [i , j - 1]这两个位置,两个位置的值进行相加 ,就是到达[i , j]位置处总共的方式;但是如果有障碍物呢?比如[i - 1, j] 或者是 [i , j - 1]其中有一个是障碍物,那么到达[i , j] 位置的所有方法就是其中一个某个不是障碍物的路径数。所以另一个有障碍的路径数为零,即遇到障碍物就不需要计算这个位置上的值,直接让它等于0。
  2. 状态转移方程:同上一题dp[i , j] = dp[i - 1, j] + [i , j - 1]。不过如果这个位置上有障碍物,那么就不需要计算这个位置上的值,直接让它等于 0 即可。
  3. 初始化:同上一题,可以添加⼀行,并且添加⼀列后,只需将dp[1][0]的位置初始化为1 即可。
  4. 填表顺序:从上往下填每⼀⾏,在填写每⼀⾏的时候从左往右。
  5. 返回值:返回dp[m][n]。

在这里插入图片描述4.代码如下

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

3. 礼物最大值(medium)

1.题目链接:礼物最大值
2.题目描述
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
在这里插入图片描述

3.问题分析
这道题和上述两道又有所不同,但都属于同种类型,所以方法大致一样。先进行状态表示:用dp[i][j] 表示:⾛到 [i, j] 位置处,此时的最⼤价值。上述两题是要算出路径数,所以将[i - 1, j] 的路径数与[i , j - 1]的路径数相加。而这道题是要求路径上的最大价值,可以将[i - 1, j] 路径上的价值数与[i , j - 1]路径上的价值数进行比较,保留两个中较大的值然后再加上grid[i,j]位置上的值即可。

  1. dp[i][j] 表⽰:⾛到 [i, j] 位置处,此时的最⼤价值
  2. 状态转移方程:从[i - 1, j] 位置,向下⾛⼀步,此时到达 [i, j] 位置能拿到的礼物价值为 dp[i - 1][j] + grid[i][j] ; 从 [i, j - 1] 位置,向右⾛⼀步,此时到达 [i, j] 位置能拿到的礼物价值为dp[i][j - 1] + grid[i][j]。
  3. 初始化:同上一题,可以添加⼀行,并且添加⼀列后,所有的值都为 0 即可。
  4. 填表顺序:从上往下填每⼀⾏,在填写每⼀⾏的时候从左往右。
  5. 返回值:返回dp[m][n]。

在这里插入图片描述

4.代码如下

class Solution
{
public:
    int maxValue(vector<vector<int>>& grid)
    {
        int m = grid.size(), n = grid[0].size();
        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]) + grid[i - 1][j - 1];

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

4. 下降路径最小和(medium)

1.题目链接:下降路径最小和
2.题目描述
给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。
在这里插入图片描述
3.问题分析
大致思路不变,先表示状态,用二维数组dp[i][j] 表⽰:到达 [i, j] 位置时,所有下降路径中的最⼩和。然后进行分析,上述所示的问题,因只能向左或向下移动,所以[i,j]的路径数是将[i - 1, j] 的路径数与[i , j - 1]的路径数相加;而这道题位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) ;以[i,j]为结尾进行分析,到达[i,j]位置的上一层应当是[i - 1, j - 1],[i - 1, j],[i - 1, j + 1]中三者最小的一个,然后加上matrix[i,j]的值,然后遍历依次填写dp表即可。其中有越界问题,如[0, j]或[i, n - 1]位置,可以用辅助结点来解决,增加两列,一列在起始,另一列在末尾;最后寻找最后一行最小的值即为下降路径最小和。

  1. dp[i][j] 表⽰:到达 [i, j] 位置时,所有下降路径中的最⼩和。
  2. dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j +1])) + matrix[i][j] 。
  3. 初始化:需要加上两列,所有的位置都初始化为⽆穷⼤,将dp表第一行初始为matrix第一行(左右两列的辅助结点是无穷大)
  4. 从上往下填每⼀⾏,在填写每⼀⾏的时候从左往右。
    4.代码如下
class Solution 
{
public:
    int minFallingPathSum(vector<vector<int>>& matrix) 
    {
        int n = matrix.size();
        //初始化dp表,全部初始化为无穷大
        vector<vector<int>> dp(n, vector<int>(n + 2, INT_MAX));
        //=将dp表第一行初始为matrix第一行
        for (int j = 0; j < n; ++j)
            dp[0][j + 1] = matrix[0][j];
        //从第二行第二列开始遍历
        for (int i = 1; i < n; ++i)
        {
            //在dp表中不是辅助结点的位置范围是1到n
            for (int j = 1; j <= n; ++j)
            {
                int x = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i - 1][j + 1]));
                dp[i][j] = x + matrix[i][j - 1]; //没有添加行,matrix对应的映射为i,j-1
            }
        }
        //寻找最后一行最小值
        int ret = dp[n - 1][0];
        for (int j = 1; j <= n; ++j)
            ret = min(ret, dp[n - 1][j]);
        return ret;
    }
};

5. 最⼩路径和(medium)

1.题目链接:最⼩路径和
2.题目描述
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
在这里插入图片描述

3.问题分析
这道题与上述题基本一致了,分析就略过。

  1. 状态表⽰:dp[i][j] 表⽰:到达 [i, j] 位置处,最⼩路径和是多少。
  2. 这道题是要求路径上的最小和,可以将[i - 1, j] 路径上的最小和与[i , j - 1]路径上的最小和进行比较,保留两个中较小的值然后再加上grid[i,j]位置上的值即可。
  3. 添加⼀⾏,并且添加⼀列后,所有位置的值可以初始化为⽆穷⼤,然后让dp[0][1] = dp[1][0] = 0 即可。
  4. 要返回的结果是dp[m][n]。因为添加了一行一列。
    4.代码如下
class Solution
{
public:
    int minPathSum(vector<vector<int>>& grid)
    {
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[0][1] = dp[1][0] = 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];
    }
};

6. 地下城游戏(hard)

1.题目链接:地下城游戏
2.题目描述
恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。
注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
在这里插入图片描述

3.问题分析
这道题已知骑士到达公主所在地,也就是右下角,骑士此时所剩健康点数为1 ,求到达终点时,起始位置生命健康值的最小点数。所以这道题应该从右下角开始遍历,至于怎么遍历,看如下分析:状态表示:dp[i][j] 表⽰:从 [i, j] 位置出发,到达终点时所需的最低初始健康点数; 以[i,j]位置为起点进行分析,有很多条路径可以到达终点,路径上有加血的,有减血的,我们要求什么?求的是血最多的时候?不是,求的是应该血量刚够过该路径的值 也就是dungeon数组中路径求和过程中各个路径负数的最大值的绝对值,所以减去 dungeon[i][j]就是所需的生命值,如果为dp结果负数,就说明能量值很大,而dp[i][j] 表⽰:从 [i, j] 位置出发,到达终点时所需的最低初始健康点数,dp[i][j]大于0,出现负数就要赋值为1。负数就代表起始位置生命值最低值为负数,这很显然不肯能为负数
位置[i + 1, j]或者 [i, j + 1]可以到达[i, j] 位置,dp的位置表示最低点数,所以选取 [i + 1, j], [i, j + 1]两者中的较小值减去dungeon[i][j]就是dp[i][j]的最小值。

  1. dp[i][j] 表⽰:从 [i, j] 位置出发,到达终点时所需的最低初始健康点数。
  2. 状态转移方程:dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];如果dp[i][j] <= 0,则dp[i][j] = 1。
  3. 初始化:在本题中,在 dp 表最后⾯添加⼀⾏,并且添加⼀列后,所有的值都先初始化为⽆穷⼤,然后让dp[m][n - 1] = dp[m - 1][n] = 1 即可。
  4. 填表顺序:需要从下往上填每⼀⾏,每⼀⾏从右往左。
  5. 返回值:dp[0][0]。
    4.代码如下
class Solution
{
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon)
    {
        int m = dungeon.size(), n = dungeon[0].size();
        // 建表 + 初始化
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
        dp[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] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
                if (dp[i][j] <= 0)
                {
                    dp[i][j] = 1;
                }
            }
        }
        // 返回结果
        return dp[0][0];
    }
};

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

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

相关文章

7.elasticsearch同步工具-logstah

1.logstah Logstash 是一个用于数据处理和转换的开源工具&#xff0c;它可以将来自不同源头的数据收集、转换、过滤&#xff0c;并将其发送到不同的目标。Logstash 是 ELK&#xff08;Elasticsearch、Logstash 和 Kibana&#xff09;技术栈的一部分&#xff0c;通常与 Elastics…

实验篇——Ka/Ks分析

实验篇——Ka/Ks分析 文章目录 前言一、名词解释二、实操1. 安装软件2. 准备文件3. 使用ParaAT2.0 KaKs_Calculator2.04. 使用TBtools软件 三、额外总结 前言 鉴定不同基因的复制模式 本文得到的共线性基因对文件 来自于上一篇文章中的LIN.collinearity共线性文件 参考文章&…

设计模式(3)抽象工厂模式

一、概述&#xff1a; 1、提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 2、结构图&#xff1a; 3、举例代码&#xff1a; &#xff08;1&#xff09; 实体&#xff1a; public interface IUser {public void insert(User user);public…

C++--动态规划两个数组的dp问题

1.最长公共子序列 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串…

Java 实现 国密SM4/ECB/PKCS7Padding对称加密解密

Java 实现 国密SM4/ECB/PKCS7Padding对称加密解密&#xff0c;为了演示方便本问使用的是IntelliJ IDEA 2022.1 (Community Edition)来构建代码的 1、pom.xml文件添加需要的jar <?xml version"1.0" encoding"UTF-8"?> <project xmlns"htt…

分布式事务(4):两阶段提交协议与三阶段提交区别

1 两阶段提交协议 两阶段提交方案应用非常广泛&#xff0c;几乎所有商业OLTP数据库都支持XA协议。但是两阶段提交方案锁定资源时间长&#xff0c;对性能影响很大&#xff0c;基本不适合解决微服务事务问题。 缺点&#xff1a; 如果协调者宕机&#xff0c;参与者没有协调者指…

SpringBoot 01 如何创建 和pom的解析

目录 1 Springboot的创建 步骤 2 项目的书写和运行 创建service包并在其下写一个service文件 项目的运行 pom文件的一些配置 parent web test 打包 打包过程 1 Springboot的创建 步骤 首先new一个新项目 然后依照如下创建 2 项目的书写和运行 创建service包并…

python接口自动化测试框架2.0,让你像Postman一样编写测试用例,支持多环境切换、多业务依赖、数据库断言等

项目介绍 接口自动化测试项目2.0 软件架构 本框架主要是基于 Python unittest ddt HTMLTestRunner log excel mysql 企业微信通知 Jenkins 实现的接口自动化框架。 前言 公司突然要求你做自动化&#xff0c;但是没有代码基础不知道怎么做&#xff1f;或者有自动化…

nginx基于端口如何配置虚拟主机

在 Nginx 中配置基于端口的虚拟主机&#xff08;也称为服务器块&#xff09;与配置基于域名的虚拟主机类似&#xff0c;但是你需要指定监听的端口。以下是基于端口的虚拟主机配置示例&#xff1a; 假设我们要配置两个不同的虚拟主机&#xff0c;一个监听 8080 端口&#xff0c…

vcomp140.dll丢失的修复方法分享,电脑提示vcomp140.dll丢失修复方法

今天&#xff0c;我的电脑出现了一个奇怪的问题&#xff0c;打开某些程序时总是提示“找不到vcomp140.dll文件”。这个问题让我非常头疼&#xff0c;因为我无法正常使用电脑上的一些重要软件。为了解决这个问题&#xff0c;我在网上查找了很多资料&#xff0c;并尝试了多种方法…

亮点!视频云存储/安防监控视频智能分析平台高空抛物AI智能检测

一、行业现状 近年来&#xff0c;高空抛物不文明事件频频发生&#xff0c;成为小区住宅的管理通病&#xff0c;也给居民的人身及财产安全带来了巨大伤害和损失。高空抛物可能导致人身事故等重大经济损失的严重危害&#xff0c;被称作“悬在城市上空的痛”。 TSINGSEE青犀AI智…

算法练习- 其他算法练习5

文章目录 宜居星球改造计划 宜居星球改造计划 yes no na 每个值为一个格子&#xff1b;每天yes的值可以向上下左右扩展一个格子&#xff0c;将no改为yes&#xff1b;矩形区域no是否可以全部转为yes&#xff0c;可以的话需要几天&#xff1f;不可以的话输出-1输入&#xff1a; …

基于FPGA的FIR低通滤波器实现(附工程源码),matlab+vivado19.2+simulation

基于FPGA的FIR低通滤波器实现(附工程源码) 文章目录 基于FPGA的FIR低通滤波器实现(附工程源码)前言一、matlab设计FIR滤波器&#xff0c;生成正弦波1.设计FIR滤波器1.生成正弦波.coe 二、vivado1.fir滤波器IP核2.正弦波生成IP核3.时钟IP核设置4.顶层文件/测试文件代码 三.simul…

Linux共享库基础及实例

共享库是将库函数打包成一个可执行文件&#xff0c;使得其在运行时可以被多个进程共享。 目标库 回顾下构建程序的一种方式&#xff1a; 将每个源文件编译成目标文件&#xff0c;再通过链接器将这些目标文件链接组成一个可执行程序。 gcc -g -c prog.c mod1.c mod2.c gcc -g …

2023国赛数学建模思路 - 案例:粒子群算法

文章目录 1 什么是粒子群算法&#xff1f;2 举个例子3 还是一个例子算法流程算法实现建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是粒子群算法&#xff1f; 粒子群算法&#xff08;Pa…

C/C++:C/C++在大数据时代的应用,以及C/C++程序员未来的发展路线

目录 1.C/C在大数据时代的应用 1.1&#xff1a;C/C数据处理 1.2&#xff1a;C/C数据库 1.3&#xff1a;C/C图像处理和计算机视觉 1.3.1&#xff1a;导读 2.C/C程序员未来的发展路线 2.1&#xff1a;图导 1.C/C在大数据时代的应用 C/C在大数据时代中仍然是一种被广泛应用的编…

如何使用Wireshark进行网络流量分析?

如何使用Wireshark进行网络流量分析。Wireshark是一款强大的网络协议分析工具&#xff0c;可以帮助我们深入了解网络通信和数据流动。 1. 什么是Wireshark&#xff1f; Wireshark是一个开源的网络协议分析工具&#xff0c;它可以捕获并分析网络数据包&#xff0c;帮助用户深入…

Python(八十五)格式化字符串

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

MySQL 主从配置

环境 centos6.7 虚拟机两台 主&#xff1a;192.168.23.160 从&#xff1a;192.168.23.163 准备 在两台机器上分别安装mysql5.6.23&#xff0c;安装完成后利用临时密码登录mysql数据修改root的密码&#xff1b;将my.cnf配置文件放至/etc/my.cnf&#xff0c;重启mysql服务进…

jsp 图书销售系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 图书销售系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…
最新文章