算法沉淀 —— 动态规划篇(路径问题)

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

前言

几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此

  • 1.、状态表示:通常状态表示分为基本分为以下两种,其中更是以第一种为甚。

    • 以i为结尾,dp[i] 表示什么,通常为代求问题(具体依题目而定)
    • 以i为开始,dp[i]表示什么,通常为代求问题(具体依题目而定)
  • 2、状态转移方程
    *以上述的dp[i]意义为以i位置为分界, 通过最近一步来分析和划分问题,由此来得到一个有关dp[i]的状态转移方程。

  • 3、dp表创建,初始化

    • 动态规划问题中,如果直接使用状态转移方程通常会伴随着越界访问等风险,所以一般需要初始化。而初始化最重要的两个注意事项便是:保证后续结果正确,不受初始值影响;下标的映射关系
    • 初始化一般分为以下两种:
      • 直接初始化开头的几个值。
      • 一维空间大小+1,下标从1开始;二维增加一行/一列
  • 4、填dp表、填表顺序:根据状态转移方程来确定填表顺序。

  • 5、确定返回值

一、不同路径1

【题目链接】:LCR 098. 不同路径
【题目】:

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?

【分析】:
 这是个二维数组问题。我们定义dp[i][j]表示机器人走到下标为[i][j]位置时的总路径数。显然机器人要走到[i][j]位置,只能从[i][j-1]向右走、[i-1][j]向下走。所以状态转移方程为dp[i][j] = dp[i-1][j] + dp[i][j-1]。 但当i = 0或j =0时,显然状态转移方程不适应,需要特殊处理。这里我们采用的办法时,横纵都新增一行。然后我们还需将dp[0][1]或dp[1][0]初始化为1。
 接下我仅需从左往右、从上到下依次填表。最后返回结果即可!!
【代码实现】:

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

二、珠宝的最高价值

【题目链接】:LCR 166. 珠宝的最高价值
【题目】:

现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为:
只能从架子的左上角开始拿珠宝每次可以移动到右侧或下侧的相邻位置到达珠宝架子的右下角时,停止拿取。
注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]。

【分析】:
 我们可以定义dp[i][j]表示从开始到[i][j]位置所能拿到的珠宝最大价值。所以要得到dp[i][j]的值,我们只需将dp[i][j-1]和dp[i-1][j]的较大值假设当前下标[i][j]的珠宝价值即可。即动态转移方程为dp[i][j] = max(dp[i-1][j] + dp[i][j-1]) + frame[i][j]。但显然当i=0或j=0时,需要特殊处理。这里还是采用横竖都各加一行。需要注意的是此时下标的映射关系(具体参考代码)。
 ;接下我仅需从左往右、从上到下依次填表。最后返回结果!!
【代码实现】:

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

三、下降路径最小和

【题目链接】:931. 下降路径最小和
【题目】:

给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。

【分析】:
 我们定义dp[i][j]表示下降到[i][j]位置时,下降路径的最小和。并且题目中已经明确表示下降到[i][j]位置有如下三种方式:
动态规划问题,算法指南,算法,动态规划,leetcode,学习方法
 显然我们容易得到状态转移方程为dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i-1][j+1])) + matrix[i-1][j-1]。但又有一个问题,当i=0、j=0、j=n时,状态转移方程会越界访问。所以我们给出的办法时加1行、加2列。同时为了不影响后续填表结果,我们将第一行初始为0,第1列和第n+1列初始化为INT_MAX(dp[0][1]、dp[0][n+1]除外)。
 接下来从左往右、从上到下依次填表。dp表填好后,最后一行的每个数都有可能是结果。我们需要依次比较,将最后一行的最小值返回!

【代码实现】:文章来源地址https://www.toymoban.com/news/detail-854914.html

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

四、地下城游戏

【题目链接】:174. 地下城游戏
【题目】:

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

【实例】:
动态规划问题,算法指南,算法,动态规划,leetcode,学习方法

输入:dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7

【分析】:
 dp问题中我们一般定义dp[i][j]表示从开始到[i][j]位置的待解结果,即骑士从[0][0]走到[i][j]所需的最低初始健康点数。但我们发现[i][j]位置后面的数据对结果存在影响。例如:dungeon = [[1, 1],[1, -100]],假设我们走到了[0][1]位置,此时dp[0][1]=1。但此时走到dungeon[1][1]时,骑士死亡。后面结果会对当前数据有影响!!因此该思路错误。
 我们可以定义dp[i][j]表示从[i][j]位置走到结尾(假设结尾下标为[m][n])骑士所需的最低健康点数。此时示意图如下:(各位懂意思就行,手残画不了图)
动态规划问题,算法指南,算法,动态规划,leetcode,学习方法
 所以我们可以得到状态转移方程为dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]。但还有两个问题:

  1. 如果dungeon[i][j]非常大,此时dp[i][j]可能为负数。此时骑士死亡,不符合要求。所以我们要进一步处理,dp[i][j] = max(1, dp[i][j])(即如果dp[i][j]为负,此时表示dungeon[i][j]j较大,我们仅需保证骑士到[i][j]位置时没有死亡即可)
  2. 如果[i][j]表示结尾呢?此时状态转移方程不适应。我们给出的办法是,最后一行、和最后一列各增一行。同时为了保存新增行列对后续填dp表不产生影响,我们其中的元素初始化为INT_MAX。同时为了保证dp[m][n]在是由状态转移方程时填表正确。我们要保证的时骑士处于[m][n]位置时还剩1个健康点数即可。所以我们将dp[m+1][n]或dp[m][n+1]初始化为1!

【代码实现】:

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

到了这里,关于算法沉淀 —— 动态规划篇(路径问题)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • LeetCode算法题解(动态规划)|LeetCoed62. 不同路径、LeetCode63. 不同路径 II

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

    2024年02月05日
    浏览(38)
  • 【算法|动态规划No.17】leetcode64. 最小路径和

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

    2024年02月07日
    浏览(35)
  • 【算法|动态规划No.6】leetcode63. 不同路径Ⅱ

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

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

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

    2024年02月12日
    浏览(27)
  • 【算法专题】动态规划之路径问题

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

    2024年01月24日
    浏览(34)
  • 【算法优选】 动态规划之路径问题——贰

    动态规划相关题目都可以参考以下五个步骤进行解答: 状态表⽰ 状态转移⽅程 初始化 填表顺序 返回值 后面题的解答思路也将按照这五个步骤进行讲解。 给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的

    2024年02月05日
    浏览(36)
  • 【算法】动态规划中的路径问题

    君兮_的个人主页 即使走的再远,也勿忘启程时的初心 C/C++ 游戏开发 Hello,米娜桑们,这里是君兮_,如果给算法的难度和复杂度排一个排名,那么动态规划算法一定名列前茅。今天,我们通过由简单到困难的两道题目带大家学会动态规划中的路径问题 好了废话不多说,开始我

    2024年02月05日
    浏览(26)
  • C++算法 —— 动态规划(2)路径问题

    每一种算法都最好看完第一篇再去找要看的博客,因为这样会帮你梳理好思路,看接下来的博客也就更轻松了。当然,我也会尽量在写每一篇时都可以让不懂这个算法的人也能边看边理解。 动规的思路有五个步骤,且最好画图来理解细节,不要怕麻烦。当你开始画图,仔细阅

    2024年02月06日
    浏览(32)
  • 基础算法之——【动态规划之路径问题】1

    今天更新动态规划路径问题1,后续会继续更新其他有关动态规划的问题!动态规划的路径问题,顾名思义,就是和路径相关的问题。当然,我们是从最简单的找路径开始! 动态规划的使用方法: 1.确定状态并定义状态数组:(i,j)代表什么意思?dp[i][j]又是什么意思? 2.确

    2024年02月07日
    浏览(29)
  • 基于sumo实现交通的拥堵预测和路径动态规划 基于机器学习或者深度学习方法动态预测各路段的拥堵指数

    基于sumo实现交通的拥堵预测和路径动态规划 实现思路: 1、基于机器学习或者深度学习方法动态预测各路段的拥堵指数。 2、采用A* Dijkstra实现车辆的路径实时动态规划 基于sumo实现交通的拥堵预测和路径动态规划 随着城市化进程的加速以及交通运输工具的不断普及,城市交

    2024年04月17日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包