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

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

  • 前言
  • 一、不同路径1
  • 二、珠宝的最高价值
  • 三、下降路径最小和
  • 四、地下城游戏

前言

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

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

    • 以i为结尾,dp[i] 表示什么,通常为代求问题(具体依题目而定)
    • 以i为开始,dp[i]表示什么,通常为代求问题(具体依题目而定)
  • 2、状态转移方程
    *以上述的dp[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]位置有如下三种方式:
在这里插入图片描述
 显然我们容易得到状态转移方程为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表填好后,最后一行的每个数都有可能是结果。我们需要依次比较,将最后一行的最小值返回!

【代码实现】:

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),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。
注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

【实例】:
在这里插入图片描述

输入: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])骑士所需的最低健康点数。此时示意图如下:(各位懂意思就行,手残画不了图)
在这里插入图片描述
 所以我们可以得到状态转移方程为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];
    }
};

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

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

相关文章

心法利器[110] | 知识文档处理和使用流程

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2023年新的文章合集已经发布&#xff0c;获取方式看这里&#xff1a;又添十万字-CS的陋室2023年文章合集来袭&#xff0c;更…

C++的缺省参数,函数重载,引用

目录 1、缺省参数&#xff08;不能在函数声明和定义中同时出现&#xff0c;若声明和定义是分开的&#xff0c;则缺省参数放在声明里面&#xff09; 1.1、缺省参数的概念 1.2、全缺省 1.3、半缺省 2、函数重载 2.1、特殊情况 2.2、特殊情况 2.3、为什么C支持函数重载而C语…

四、C语言中的数组:二维数组

四、C语言中的数组&#xff1a;二维数组 本章的学习内容如下&#xff1a; 四、C语言中的数组&#xff1a;数组的创建与初始化 四、C语言中的数组&#xff1a;数组的输入与元素个数 C语言—第6次作业—十道代码题掌握一维数组 四、C语言中的数组&#xff1a;二维数组 我们可以…

学习SpringBoot笔记--知识点(2)

目录 数据访问 基础特性 自定义banner Profiles Profiles组件 Profiles配置文件 外部化配置 单元测试 数据访问 整合SSM场景 SpringBoot 整合 Spring&#xff0c;SpringMVC&#xff0c;MyBatis 进行数据访问场景开发 需要的依赖&#xff1a; <!-- web启动…

遇到了问题,Firepower 2140配置带外IP时报错 commit-buffer failed

onsite we have a cisco firepower 2140 device which run ASA as we try to modify the 2140 OOB mgmt ip by CLI, we got an error why ? 经过查询发现&#xff0c;需要进入ASA里面打上以下这条命令&#xff0c;并重启ASA 1 修改模式并重启 ciscoasa# configure termina…

注册、配置中心-微服务小白入门(2)

Nacos 已经下载安装并且使用了&#xff0c;那么看如何使用&#xff1a; Nacos 注册及配置&#xff0c;以下是一个服务启动后注册到nacos&#xff0c;同时&#xff0c;把该服务的相关配置&#xff0c;写到nacos之中 1、nacos设置 命名空间中&#xff0c;添加对应的服务命名空间…

agent利用知识来做规划:《KnowAgent: Knowledge-Augmented Planning for LLM-Based Agents》笔记

文章目录 简介KnowAgent思路准备知识Action Knowledge的定义Planning Path Generation with Action KnowledgePlanning Path Refinement via Knowledgeable Self-LearningKnowAgent的实验结果 总结参考资料 简介 《KnowAgent: Knowledge-Augmented Planning for LLM-Based Age…

CharacterController.Move called on inactive controller

【问题背景】 Unity3D中开发物体的移动&#xff0c;实现代码如下&#xff1a; public class TargetController : MonoBehaviour {private CharacterController character;private float speedRate 4f;private void Start(){character GetComponent<CharacterController&…

第十二届蓝桥杯JavaB组省赛真题 - 时间显示

解题思路&#xff1a; 数量级较大&#xff0c;需要使用long类型 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);long num scan.nextLong();long allseconds num / 1000;long seconds allse…

ROS机器人入门第四课:话题通信

文章目录 ROS机器人入门第四课&#xff1a;话题通信一、话题通信概述&#xff08;一&#xff09;概念&#xff08;二&#xff09;作用 二、话题通信基本操作需求:分析:流程:&#xff08;一&#xff09;发布方解释一些关键的ROS函数和概念&#xff1a; &#xff08;二&#xff0…

如何使用WordPress插件保护网站的安全

前段时间我们的网站受到了黑客的攻击&#xff0c;网站丢失了一些重要的数据&#xff0c;为了防止这种情况的再次发生&#xff0c;我们准备将网站全部迁移到高防服务器&#xff0c;经过一番对比后&#xff0c;我们选择了Hostease提供的高防服务器。它可以有效地抵御各种类型的网…

网络七层模型:理解网络通信的架构(〇)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

开箱即用的中后台管理模版,建议收藏!

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 原文作者&#xff1a;前端充电宝 大家好&#xff0c;我是白特。 今天来推荐几款开箱即用的中后台管理模版&#xff01; Vue Element Admin vue-element-admin 是一个后台前端解决方案&#xff0c;它基于 vue 和 …

WMS仓储管理系统如何优化供应链管理

随着信息技术的快速发展和市场竞争的加剧&#xff0c;优化供应链管理已成为企业提升竞争力的关键。WMS仓储管理系统作为供应链管理的核心工具&#xff0c;其在优化供应链过程中的作用日益凸显。本文将深入探讨WMS仓储管理系统如何优化供应链管理。 首先&#xff0c;WMS仓储管理…

pdfjs 实现给定pdf数据切片高亮并且跳转

pdfjs 实现给定pdf数据切片高亮并且跳转 pdfjs 类的改写基本展示需求的实现高亮功能的实现查询功能分析切片数据处理 pdfjs 类的改写 需求&#xff1a; pdf文件被解析成多个分段&#xff0c;每个分段需要能够展示&#xff0c;并且通过点击分段实现源pdf内容的高亮以及跳转需求…

Oracle数据库入门第三课(函数)

前面二白讲了一些简单的查询语句&#xff0c;仅仅知道查询语句的语法是不够的&#xff0c;要想实现更多的需求&#xff0c;更重要的是函数的使用&#xff0c;这节课我们简单说一下一些函数的使用。 一、函数的分类 什么叫做函数? 函数就是用来实现某种功能的,提前声明好的代…

微博修改密码后无法通过微博开放接口发送微博

生产环境&#xff0c;因密码修改导致授权失效致接口发送微博失效&#xff01;内部网站编辑完博文后无法发送微博。在修改密码时&#xff0c;有提示授权应用失效&#xff0c;操作人员不清晰情况&#xff0c;直接忽视。 微博应用开放接口----》微博转发博文接口文档 无示例 遗憾…

淘宝API接口推荐:淘宝app商品详情数据接口

淘宝的商品详情API接口是一种技术工具&#xff0c;它允许开发者通过编程的方式获取淘宝平台上商品的详情页面的数据。这些数据对于电商智能决策至关重要&#xff0c;因为它们可以提供关于消费者偏好、商品质量和市场趋势的宝贵信息。 淘宝天猫API列表 item_get 获得商品详情i…

多线程死锁,java内存模型,wait、notify方法

死锁出现的第一种情况 可重入 同一个线程针对同一个锁连续继续加锁多次的行为。如果发生了死锁情况&#xff0c;那就是发生了不可重入&#xff0c;反之不会发生死锁&#xff0c;就是可重入的。 当进行多次加锁会发生什么情况 在这个方法中实现了在外面对方法的加锁&#xff08;…

操作系统的理解|冯·若依曼体系结构|进程的状态

操作系统的理解 冯诺伊曼体系结构为什么必须通过内存然后到cpu存储金字塔冯诺伊曼结构的改进在哪&#xff1f;我们可不可以全部用寄存器来做存储器在硬件数据流动角度学以致用&#xff1a;解释程序运行为什么要加载到内存程序没被运行之前存在哪里&#xff1f; 操作系统概念广义…