60题学会动态规划系列:动态规划算法第二讲

这篇具有很好参考价值的文章主要介绍了60题学会动态规划系列:动态规划算法第二讲。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

都是路径问题~

文章目录

  • 1.不同路径
  • 2.不同路径II
  • 3.礼物的最大价值
  • 4.下降路径最小和
  • 5.最小路径和

1.不同路径

力扣链接:力扣

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

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

问总共有多少条不同的路径?

60题学会动态规划系列:动态规划算法第二讲

 本题中的重点在于:机器人每次只能向下或向右走,下面我们画图分析一下:

60题学会动态规划系列:动态规划算法第二讲

如上图,我们要求终点的位置的路径总和其实只要计算终点位置的上一个位置和终点位置的左边一个位置的方法总和,因为只有这两个位置可以一步到终点,而计算这两个位置的方法数也同理,只需要求上面那个位置和左边那个位置的和,所以我们的状态可以表示成到达这个位置的路径总和

1.状态表示

dp[i][j]表示到达i,j位置的路径总和.

2.状态转移方程

dp[i][j] = dp[i-1][j] + dp[i][j-1]

3.初始化

还记得我们上一篇最后讲的初始化的技巧吗?只需要多开虚拟位置就可以解决越界的问题。首先第一行的值求dp[i-1][j]的时候会越界,第一列的值求dp[i][j-1]的时候会越界,所以我们只需要多开一行一列就能完成初始化:

60题学会动态规划系列:动态规划算法第二讲

那么这个多开的虚拟位置如何初始化呢?我们的虚拟位置的值一定不可以影响最终结果,首先第一行不管是哪一个位置他们的方法数都为1,因为这个机器人只能向右或者向下。然后第一列也同理所有的方法数都为1,这个时候我们看第一行最右边的位置,这个位置需要上面位置的方法数和左边位置的方法数之和,首先起点位置是一种方法,所以我们的虚拟位置一定为0,但是为了保证起点为1,所以只需要让起点的上一个位置或者左边的位置为1即可,如下图:

60题学会动态规划系列:动态规划算法第二讲

4.填表顺序

整体从上往下,每一行从左往右依次填表

5.返回值

返回dp表最后一个位置

class Solution {
public:
    int uniquePaths(int m, int n) {
      //创建dp表
      vector<vector<int>> dp(m+1,vector<int>(n+1,0));
      //初始化
      dp[1][0] = 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];
    }
};

 要注意:我们的虚拟位置是不进行动态计算的,所以实际上的位置是从1,1开始的,从上面的图我们也可以发现。刚开始二维数组初始化为0会方便很多。

2.不同路径II

力扣链接:力扣

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

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

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

网格中的障碍物和空位置分别用 1 和 0 来表示。

60题学会动态规划系列:动态规划算法第二讲

 此题与上一题一样,只不过障碍物的位置方法数为0.

1.状态表示

dp[i][j]表示到达i,j位置的方法数。

2.状态转移方程

当dp[i][j]!=1时,dp[i][j] = dp[i-1][j] + dp[i][j-1]

当dp[i][j]==1时,dp[i][j]==0

3.初始化

与上一题一样

4.填表顺序

与上一题一样

5.返回值

与上一题一样

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
       //创建dp表
       int row = obstacleGrid.size();
       int col = obstacleGrid[0].size();
       vector<vector<int>> dp(row+1,vector<int>(col+1,0));
       //初始化
       dp[1][0] = 1;
       //状态转移方程
       for (int i = 1;i<=row;i++)
       {
           for (int j = 1;j<=col;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[row][col];
    }
};

注意:dp表由于多开了虚拟位置所以与原数组映射整体向右下角移动了一位。

3.礼物的最大价值

力扣链接:力扣

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

60题学会动态规划系列:动态规划算法第二讲

 此题实际上还是路径问题,下面我们画个图演示:

60题学会动态规划系列:动态规划算法第二讲

其实做了这么多道动态规划题我们也有些经验了,本题的条件还是每次只能向下或者向右移动,那么到达右下角拿到的最大价值的礼物其实就是右下角上面位置和右下角左边位置中拿到的礼物的价值的最大值再加上右下角的礼物价值,下面我们直接按步骤解题:

1.状态表示

dp[i][j]表示到达i,j位置的最大礼物价值

2.状态转移方程

dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + 原数组[i][j]

3.初始化

我们还是用多开虚拟位置的方式初始化,下面我们画图演示:

60题学会动态规划系列:动态规划算法第二讲

 题目中有一个小细节:所有礼物的价值都是大于0的,而我们的虚拟位置是不能影响结果的,起点位置的价值就是1不能被影响那么虚拟位置只能是0了,当我们填0后发现所有的结果都是正确的。

60题学会动态规划系列:动态规划算法第二讲

4.填表

整体从上往下,每一行从左向右依次填表

5.返回值

返回dp表最后一个位置 

class Solution {
public:
    int maxValue(vector<vector<int>>& grid) {
       //创建dp表
       int row = grid.size();
       int col = grid[0].size();
       //初始化
       vector<vector<int>> dp(row+1,vector<int>(col+1,0));
       //状态转移方程
       for (int i = 1;i<=row;i++)
       {
           for (int j = 1;j<=col;j++)
           {
               dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + grid[i-1][j-1];
           }
       }
       return dp[row][col];
    }
};

4.下降路径最小和

力扣链接:力扣

给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径  最小和 。

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)(row + 1, col) 或者 (row + 1, col + 1) 。

60题学会动态规划系列:动态规划算法第二讲

 此题很简单,从第一行任选一个位置开始向下加和,向下的规则是下面相邻的三个位置,直到最后一行的最小路径和,理解了这个条件我们的状态表示就很简单了。

1.状态表示

dp[i][j]表示到达i,j位置的最小下降和

2.状态转移方程

我们的dp[i][j]既然是到达i,j位置的最小下降和,那么状态转移方程一定是看从哪几个位置可以到达i,j位置并且求最小值。

dp[i][j] = min(min(dp[i-1][j-1],dp[i-1][j]),dp[i-1][j+1]) + 原数组[i][j]

3.初始化

我们依次用开虚拟位置的方式,下面我们画个图:

60题学会动态规划系列:动态规划算法第二讲

 越界的位置就是我画圈的位置,那么我们如何初始化才不会影响结果呢?这里一定不能将虚拟位置初始化为0,因为题目中是有负数的!:

60题学会动态规划系列:动态规划算法第二讲

 所以我们要求最小值不影响原来的位置的值,只能将虚拟位置初始化为无穷大,这样虚拟位置就一定不会是最小值了。如下图:

60题学会动态规划系列:动态规划算法第二讲

 首先第一行是不需要计算的,所以第一行的值我们要保持原始结果,那么上面虚拟位置就不能影响我们第一行的值,所以第一行的虚拟位置初始化为0.第一列和最后一列在计算的时候不能影响我们求最小值,所以我们将这两列虚拟位置初始化为正无穷。

4.填表顺序

从上到下,每一行从左向右

5.返回值

我们的状态表示是到达i,j位置的最小和,那么只要找到dp表最后一行的最小值即可

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
       //创建dp表
       int row = matrix.size();
       int col = matrix[0].size();
       vector<vector<int>> dp(row+1,vector<int>(col+2,INT_MAX));
       //初始化
       for (int i = 0;i<col+2;i++)
       {
           dp[0][i] = 0;
       }
       //状态转移方程
       for (int i = 1;i<=row;i++)
       {
           for (int j = 1;j<=col;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 = dp[row][0];
       for (int i = 1;i<=col;i++)
       {
           if (dp[row][i]<min)
           {
               min = dp[row][i];
           }
       }
       return min;
    }
};

 我们初始化vector的时候全部初始化为正无穷会比初始化0方便很多,初始化0我们要修改两列的值,初始化正无穷只需要修改第一行的值,将第一行初始化为0,由于我们的min函数只能是两个参数,所以我们先求前两个的最小值再和最后一个值求一下最小值即可,最后我们将dp表最后一行的最小元素拿出来即可。注意:行列的判断条件要画图去看,因为我们实际上是不算虚拟位置的所以一定要控制好判断条件。

5.最小路径和

力扣链接:力扣

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

说明:每次只能向下或者向右移动一步。

60题学会动态规划系列:动态规划算法第二讲

这道题的条件和之前一样,都是只能往下或者往右走,在这种条件下到达右下角,那么右下角的最小值一定是右下角的上面位置或者右下角的左边位置的最小值。

1.状态表示

dp[i][j]表示从起点到达i,j位置的最小值。

2.状态转移方程

能到达i,j位置一定是[i-1][j]和[i][j-1]这两个位置

dp[i][j] = min(dp[i-1][j],dp[i][j-1])

3.初始化

我们继续用开虚拟位置的思想,根据状态转移方程我们知道能越界的位置只有第一行和第一列,所以我们只需要多开一行和多开一列即可:

60题学会动态规划系列:动态规划算法第二讲

 我们的起始位置的最小值只能是1,所以起始位置的上面的位置和左边的位置不能影响起始位置的值,所以将1的上面和左边初始化为0,其他位置为了不影响计算最小值所以要初始化为无穷大。

4.填表

从上往下,每行从左向右依次填表

5.返回值

dp表最后一个位置的值。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
      //创建dp表
      int row = grid.size();
      int col = grid[0].size();
      vector<vector<int>> dp(row+1,vector<int>(col+1,INT_MAX));
      dp[0][1] = dp[1][0] = 0;
      //状态转移方程
      for (int i = 1;i<=row;i++)
      {
          for (int j = 1;j<=col;j++)
          {
              dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i-1][j-1];
          }
      }
      return dp[row][col];
    }
};

以上就是我们动态规划第二篇的5道题,本次的习题都是路径问题,对于动态规划中的路径问题,我们只要掌握了规律就会非常简单。文章来源地址https://www.toymoban.com/news/detail-471560.html

到了这里,关于60题学会动态规划系列:动态规划算法第二讲的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数学建模】《实战数学建模:例题与讲解》第二讲-线性规划(含Matlab代码)

    如果这篇文章对你有帮助,欢迎点赞与收藏~ 线性规划(Linear Programming,LP)是一种在数学规划领域中应用广泛的最优化问题解决方法。其基本思想是在一系列约束条件下,通过建立线性数学模型来描述目标函数,以求得使目标函数最大或最小的决策变量值。线性规划在运筹学

    2024年02月04日
    浏览(34)
  • 从零开始的三维激光雷达SLAM教程第二讲(搭建Gazebo仿真环境,并添加动态障碍物)

    毕业设计打算做三维激光SLAM,记录一些学习历程,也给后面人一点帮助。本教程不涉及SLAM基本概念(如果没有自行补充),主要包含以下几部分内容。 搭建激光SLAM的运行环境并运行数据集 在Gazebo中构建仿真地图并添加动态障碍物,使用仿真小车采集激光数据。 A-LOAM详解,

    2024年02月01日
    浏览(36)
  • “算法详解”系列第3卷贪心算法和动态规划出版

    “算法详解”系列图书共有4卷,目前1到3卷已经出版。最新出版的是第3卷—贪心算法和动态规划。 “算法详解”系列图书共有4卷,本书是第3卷—贪心算法和动态规划。其中贪心算法主要包括调度、最小生成树、集群、哈夫曼编码等,动态规划主要包括背包、序列对齐、最短

    2024年02月13日
    浏览(26)
  • 算法系列--动态规划--背包问题(1)--01背包介绍

    💕\\\"趁着年轻,做一些比较cool的事情\\\"💕 作者:Lvzi 文章主要内容:算法系列–动态规划–背包问题(1)–01背包介绍 大家好,今天为大家带来的是 算法系列--动态规划--背包问题(1)--01背包介绍 背包问题是动态规划中经典的一类问题,经常在笔试面试中出现,是非常 具有区分度 的题

    2024年04月16日
    浏览(37)
  • 算法系列--动态规划--背包问题(3)--完全背包介绍

    💕\\\"Su7\\\"💕 作者:Lvzi 文章主要内容:算法系列–动态规划–背包问题(3)–完全背包介绍 大家好,今天为大家带来的是 算法系列--动态规划--背包问题(3)--完全背包介绍 链接: 完全背包 可以发现完全背包问题和01背包问题还是特比相似的 分析: 完全背包问题 是 01背包问题 的推广

    2024年04月25日
    浏览(31)
  • 算法沉淀——动态规划篇(子数组系列问题(下))

    几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此 1.、状态表示:通常状态表示分为以下两种,其中更是第一种为主。 以i为结尾 ,dp[i] 表示什么,通常为代求问题(具体依题目而定) 以i为开始 ,dp[i]表示什么,通常为代求问题(具体依题目而

    2024年04月14日
    浏览(41)
  • 【算法|动态规划系列No.5】leetcode62. 不同路径

    个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年02月12日
    浏览(32)
  • 〖动态规划60题〗泰波纳契数列模型

    题目链接 :第N个泰波那契数 题目描述 : 泰波那契序列 Tn 定义如下: T0 = 0, T1 = 1, T2 = 1, 且在 n = 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2 给你整数 n,请返回第 n 个泰波那契数 Tn 的值。 1. 状态表示 在解任何一道动态规划题目时,我们都需要先给出一张 dp 表,用来存储某种状态。 dp

    2024年02月12日
    浏览(25)
  • 【手撕算法|动态规划系列No.4】leetcode91. 解码方法

    个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年02月12日
    浏览(31)
  • 【我们一起60天准备考研算法面试(大全)-第二十九天 29/60】【二进制】

    专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录) 文章字体风格: 红色文字表示:重难点★✔ 蓝色文字表示:思路以及想法★✔ 如果大家觉得有帮助的话,感谢大家帮

    2024年02月15日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包