算法训练之动态规划(五)——简单多状态问题

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥
♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥
♥♥♥我们一起努力成为更好的自己~♥♥♥
♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥
♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥
✨✨✨✨✨✨ 个人主页✨✨✨✨✨✨
这一篇博客我们继续来看看动态规划系列里面的简单多状态问题,准备好了吗~我们发车去探索奥秘啦~🚗🚗🚗🚗🚗🚗
目录
粉刷房子
买卖股票的最佳时机(含冷冻期)
粉刷房子
粉刷房子


可以看到题目要求给房子上颜色,并且相邻的房子颜色不能相同~这显然是是一个多状态的问题,接下来我们来一步步分析一下~
分析:
1、状态表示
题目要求:相邻的房子颜色不能相同,每一个房子有三种颜色可以选择~我们创建三个dp表来进行表示,事实上,题目给出的二维数组,行号就是房子号数,列号是涂某一种颜色的花费,我们也可以用这样一个二维数组来形成我们的dp表~每一个房子都有三种不同的情况~
结合这里的题目要求+经验:
dp表中的dp1[i][0]表示为到达该位置并且选择该位置选择涂红色的最小花费~
dp表中的dp1[i][1]表示为到达该位置并且选择该位置选择涂蓝色的最小花费~
dp表中的dp1[i][2]表示为到达该位置并且选择该位置选择涂绿色的最小花费~
2、状态转移方程
我们以离【i】位置最近的状态分析状态转移方程,处理dp表
1、
dp【i】【0】选择【i】位置涂红色,那么说明前面的位置是一定不可以涂蓝色和绿色的,取两者最小值再加上当前位置涂红色的花费,那么
dp[i][0]=min(dp[i-1][1],dp[i-1][2])+nums[i][0]
2、
dp【i】【1】选择【i】位置涂蓝色,那么说明前面的位置是一定不可以涂红色和绿色的,取两者最小值再加上当前位置涂蓝色的花费,那么
dp[i][1]=min(dp[i-1][0],dp[i-1][2])+nums[i][1]
3、
dp【i】【2】选择【i】位置涂绿色,那么说明前面的位置是一定不可以涂蓝色和红色的,取两者最小值再加上当前位置涂绿色的花费,那么
dp[i][2]=min(dp[i-1][0],dp[i-1][1])+nums[i][2]
3、初始化
我们可以看到,状态转移方程里面有i-1当i=0的时候显然会出现越界的情况,所以我们需要进行初始化
结合前面如果不想初始化太麻烦,我们可以多申请一些空间,但是事实上这个题目初始化比较简单,直接初始化dp[0][0],dp[0][1],dp[0][2]就可以了,所以我们直接进行初始化~
dp[0][0]就是选择0位置涂红色花费nums[0][0], dp[0][1]就是选择0位置涂蓝色花费nums[0][1], dp[0][2]就是选择0位置涂绿色花费nums[0][2]那么我们初始化结果就是
dp[0][0]=nums[0][0] , dp[0][1]=nums[0][1] , dp[0][2]=nums[0][2]
4、填表顺序
我们这里的逻辑是从前面依次推出后面的,所以填表顺序是从前往后
5、返回结果
这里返回结果是到最后一个房子的最小花费,最后一个房子有三种情况,一种是选择涂红色,一种是选择涂蓝色,还有一种是选择涂绿色,返回三种情况最小值就可以了,即返回min(min(dp[m-1][0],dp[m-1][1]),dp[m-1][2])
注意点:结合题目给出的范围,这里不需要处理边界情况~
代码实现:
class Solution
{
public:int minCost(vector<vector<int>>& costs){//1、创建dp表int m = costs.size();//房子号int n = costs[0].size();//颜色vector<vector<int>> dp(m, vector<int>(n));//2、初始化dp[0][0] = costs[0][0];dp[0][1] = costs[0][1];dp[0][2] = costs[0][2];//3、填表for (int i = 1; i < m; i++){dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i][0];dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i][1];dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i][2];}//4、返回结果return min(min(dp[m - 1][0], dp[m - 1][1]), dp[m - 1][2]);}
};

顺利通过~
我们也可以采用有趣提到的增加虚拟节点的方法,这里相当于多增加一个空房子,有下面两个注意点:
1、虚拟节点值是多少?
虚拟节点会影响到第一个房子的最小花费,事实上,到第一个房子的最小花费也就是第一个房子的花费,不想让虚拟节点影响,就把虚拟节点值设置为0~
2、注意下标映射关系
相当于增加了一个房子,注意与原来的数组的下标映射~
代码实现:
class Solution
{
public:int minCost(vector<vector<int>>& costs){//使用虚拟节点//1、创建dp表int m = costs.size();int n = costs[0].size();//也可以直接写为已知的3vector<vector<int>> dp(m + 1, vector<int>(n));//2、初始化虚拟节点dp[0][0] = 0;dp[0][1] = 0;dp[0][2] = 0;//3、填表for (int i = 1; i <= m; i++){//注意下标映射关系dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0];dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2];}//4、返回结果return min(min(dp[m][0], dp[m][1]), dp[m][2]);}
};

顺利通过~不难发现,代码量其实是差不多的,大家选择自己喜欢的方式就好~
买卖股票的最佳时机(含冷冻期)
买卖股票的最佳时机(含冷冻期)


这个题目显然是一个多状态问题,那么我们首先得分析它有哪几个状态:
1、买入状态(也就是手上有股票的状态,可以进行卖出)
2、冷冻期状态(不可以进行买入)
3、可以交易的状态(可以进行买入)
接下来画图分析这几个状态之间的关系(也就是讨论状态相互之间是否可达以及是否可以自己到自己)

知道了这三个状态之间的关系,我们就可以利用动态规划的思想进行分析:
1、状态表示
题目要求:既然有三个状态,那么我们就需要创建三个dp表表示不同位置可能的状态~
结合这里的题目要求+经验:
dp1表中的dp1[i]表示为到达该位置进行操作后处于买入状态的最大利润~
dp2表中的dp2[i]表示为到达该位置进行操作后处于可交易状态的最大利润~
dp3表中的dp3[i]表示为到达该位置进行操作后处于冷冻期状态的最大利润~
注意是在该位置进行操作后处于什么状态,而不是到达该位置是什么状态,这样会比较麻烦~
2、状态转移方程
我们以离【i】位置最近的状态分析状态转移方程,处理dp表
1、
怎么样会处于买入状态呢?结合前面的画图分析可能是前一天可交易状态下,在今天买入股票变成买入状态;也可能是前一天买入状态下,今天什么都不干依然是买入状态,取两种情况的较大值~
dp1表状态转移方程:
dp1[i]=max(dp1[i-1],dp2[i-1]-prices[i]);
2、
怎么样会处于可交易状态呢?结合前面的画图分析可能是前一天冷冻期状态,今天就是可交易的状态;也可能是前一天可交易状态下,今天什么都不干依然是可交易状态,取两种情况的较大值~
dp2表状态转移方程:
dp2[i]=max(dp2[i-1],dp3[i-1]);
3、
怎么样会处于冷冻期状态呢?结合前面的画图分析可能是前一天处于买入状态,在今天进行卖出也就处于冷冻期状态了~没有其他情况
dp3表状态转移方程:
dp3[i]=dp1[i-1]+prices[i];
3、初始化
我们可以看到,状态转移方程里面有i-1当i=0的时候显然会出现越界的情况,所以我们需要进行初始化
结合前面如果不想初始化太麻烦,我们可以多申请一些空间,但是事实上这个题目初始化比较简单,直接初始化dp1[0],dp2[0],dp3[0]就可以了,所以我们直接进行初始化~
dp1[0]就是第一天操作后处于买入状态,那么利润为-prices[0];
dp2[0]就是第一天操作后处于可交易状态,那就是什么都不干,那么利润为0;
dp3[0]就是第一天操作后处于冷冻期状态,这是不可能的,那么利润为0;
那么我们初始化结果就是
dp1[0]=-prices[0] , dp2[0]=0 , dp3[0]=0
4、填表顺序
我们这里的逻辑是从前面依次推出后面的,所以填表顺序是从前往后
5、返回结果
这里返回结果是到最后一天的最大利润,最后一天有三种情况,返回三种情况最大值就可以了,即返回return max(max(dp1[n-1],dp2[n-1]),dp3[n-1]);
当然,最后一天是不可能还处于买入状态的,这样就亏了,也就可以返回return max(dp2[n-1],dp3[n-1]);
注意点:结合题目给出的范围,这里不需要处理边界情况~
代码实现:
class Solution
{
public:int maxProfit(vector<int>& prices) {//1、创建dp表int n=prices.size();vector<int> dp1(n);//买入状态vector<int> dp2(n);//可以交易状态vector<int> dp3(n);//冷冻期状态//2、初始化dp1[0]=-prices[0];dp2[0]=0;dp3[0]=0;//3、填表for(int i=1;i<n;i++){dp1[i]=max(dp1[i-1],dp2[i-1]-prices[i]);dp2[i]=max(dp2[i-1],dp3[i-1]);dp3[i]=dp1[i-1]+prices[i];}//4、返回结果//return max(max(dp1[n-1],dp2[n-1]),dp3[n-1]);return max(dp2[n-1],dp3[n-1]);}
};

顺利通过~
除了这种创建dp表的方式,我们也可以像前面那样创建二维数组(n*3)来实现三个dp表~
我们重新来进行分析一下:
1、状态表示
题目要求:既然有三个状态,那么我们就需要创建三个dp表表示不同位置可能的状态~这里创建一个n*3的二维数组来表示~
结合这里的题目要求+经验:
dp表中的dp[i][0]表示为到达该位置进行操作后处于买入状态的最大利润~
dp表中的dp[i][1]表示为到达该位置进行操作后处于可交易状态的最大利润~
dp表中的dp[i][2]表示为到达该位置进行操作后处于冷冻期状态的最大利润~
2、状态转移方程
我们以离【i】位置最近的状态分析状态转移方程,处理dp表
1、
怎么样会处于买入状态呢?结合前面的画图分析可能是前一天可交易状态下,在今天买入股票变成买入状态;也可能是前一天买入状态下,今天什么都不干依然是买入状态,取两种情况的较大值~
dp表状态转移方程:
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
2、
怎么样会处于可交易状态呢?结合前面的画图分析可能是前一天冷冻期状态,今天就是可交易的状态;也可能是前一天可交易状态下,今天什么都不干依然是可交易状态,取两种情况的较大值~
dp表状态转移方程:
dp[i][1]=max(dp[i-1][1],dp[i-1][2]);
3、
怎么样会处于冷冻期状态呢?结合前面的画图分析可能是前一天处于买入状态,在今天进行卖出也就处于冷冻期状态了~没有其他情况
dp表状态转移方程:
dp[i][2]=dp[i-1][0]+prices[i];
3、初始化
我们可以看到,状态转移方程里面有i-1当i=0的时候显然会出现越界的情况,所以我们需要进行初始化
结合前面如果不想初始化太麻烦,我们可以多申请一些空间,但是事实上这个题目初始化比较简单,直接初始化dp[0][0],dp[0][1],dp[0][2]就可以了,所以我们直接进行初始化~
dp[0][0]就是第一天操作后处于买入状态,那么利润为-prices[0];
dp[0][1]就是第一天操作后处于可交易状态,那就是什么都不干,那么利润为0;
dp[0][2]就是第一天操作后处于冷冻期状态,这是不可能的,那么利润为0;
那么我们初始化结果就是
dp[0][0]=-prices[0];//买入状态
dp[0][1]=0;//可交易状态
dp[0][2]=0;//冷冻期状态
4、填表顺序
我们这里的逻辑是从前面依次推出后面的,所以填表顺序是从前往后
5、返回结果
这里返回结果是到最后一天的最大利润,最后一天有三种情况,返回三种情况最大值就可以了,即返回return max(max(dp[n-1][0],dp[n-1][1]),dp[n-1][2]);
当然,最后一天是不可能还处于买入状态的,这样就亏了,也就可以返回return max(dp[n-1][1],dp[n-1][2]);
代码实现:(逻辑都是差不多的,只不过实现上有区别)
class Solution
{
public:int maxProfit(vector<int>& prices){//1、创建二维数组dp表int n = prices.size();vector<vector<int>> dp(n, vector<int>(3, 0));//2、初始化dp[0][0] = -prices[0];//买入状态dp[0][1] = 0;//可交易状态dp[0][2] = 0;//冷冻期状态//3、填表for (int i = 1; i < n; i++){dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);dp[i][2] = dp[i - 1][0] + prices[i];}//4、返回结果return max(max(dp[n - 1][0], dp[n - 1][1]), dp[n - 1][2]);//return max(dp[n-1][1],dp[n-1][2]);}
};

顺利通过~
♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥
♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥
✨✨✨✨✨✨个人主页✨✨✨✨✨✨
相关文章:
算法训练之动态规划(五)——简单多状态问题
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
C++ 大数相加(简要版)
#include <algorithm> #include <iterator> class Solution { public:/*** 计算两个数之和* param s string字符串 表示第一个整数* param t string字符串 表示第二个整数* return string字符串*/string solve(string s, string t) {// 处理空字符串的情况…...
SVMSPro分布式综合安防管理平台-->以S3存储革新,开启智能安防新纪元
SVMSPro分布式综合安防管理平台–>以S3存储革新,开启智能安防新纪元 在数字化转型浪潮下,企业安防管理正面临海量数据存储、跨区域协同以及数据安全的严峻挑战。如何实现高效、弹性、低成本的存储扩容?如何确保关键录像数据万无一失&…...
KV Cache大模型推理加速功能
KV Cache KV Cache是大模型标配的推理加速功能,也是推理过程中,显存资源巨大开销的元凶之一。在模型推理时,KV Cache在显存占用量可达30%以上。 目前大部分针对KV Cache的优化工作,主要集中在工程上。比如著名的VLLM,…...
速盾:高防CDN节点对收录有影响吗?
引言 搜索引擎收录是网站运营中至关重要的环节,它直接影响着网站的曝光度和流量。近年来,随着网络安全威胁的增加,许多企业开始采用高防CDN(内容分发网络)来保护其网站免受DDoS攻击和其他形式的网络攻击。然而&#x…...
脑科学与人工智能的交叉:未来智能科技的前沿与机遇
引言 随着科技的迅猛发展,脑科学与人工智能(AI)这两个看似独立的领域正在发生深刻的交汇。脑机接口、神经网络模型、智能机器人等前沿技术,正带来一场跨学科的革命。这种结合不仅推动了科技进步,也在医疗、教育、娱乐等…...
Linux 系统中从源码编译安装软件
以下是 Linux 系统中 从源码编译安装软件 的详细步骤和注意事项,帮助你掌握这一高级操作技能: 一、编译安装的核心流程 1. 下载源码包(通常为 .tar.gz/.tar.bz2/.tar.xz) 2. 解压源码包 3. 进入源码目录 4. 配置编译参数…...
docker 运行自定义化的服务-后端
docker 运行自定义化的服务-前端-CSDN博客 运行自定义化的后端服务 具体如下: ①打包后端项目,形成jar包 ②编写dockerfile文件,文件内容如下: # 使用官方 OpenJDK 镜像 FROM jdk8:1.8LABEL maintainer"ATB" version&…...
基于关键字定位的自动化PDF合同拆分
需求背景: 问题描述: 我有一份包含多份合同的PDF文件,需要将这些合同分开并进行解析。 传统方法(如以固定页数作为分割点)不够灵活,无法满足需求。 现有方法的不足: 网上找到的工具大多依赖手动…...
spring security 使用auth2.0
在 Spring Security 中集成 OAuth 2.0 可以实现安全的第三方认证和资源保护。以下是完整的配置指南和代码示例: 一、OAuth 2.0 核心概念 角色作用资源所有者用户(授权访问资源的人)客户端应用(如Web、移动端)授权服务…...
NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)
记忆化搜索 在搜索的过程中,如果搜索树中有很多重复的结点,此时可以通过⼀个"备忘录",记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时,直接在"备忘录"⾥⾯找结果。其中,搜索树中的⼀个⼀个结点…...
ubuntu 服务器版本常见问题
一、系统安装与初始化 1. 安装过程中断或失败 原因:镜像损坏、硬件兼容性、磁盘分区错误。 解决: 验证 ISO 文件的完整性(计算 SHA256 校验和)。 检查 BIOS/UEFI 设置(禁用 Secure Boot)。 使用手动分区模式,确保根分区(/)和 EFI 分区(如有)正确配置。 2. 系…...
【时时三省】(C语言基础)用switch语句实现多分支选择结构 例题
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 例题: 用switch语句处理菜单命令。在许多应用程序中,用菜单对流程进行控制,例如从键盘输入一个 A 或 a 字符,就会执行A操作,输入一…...
全域数字化:从“智慧城市”到“数字生命体”的进化之路
一、国家战略下的城市数字化浪潮 2024年5月,国家四部委联合发布《关于深化智慧城市发展 推进城市全域数字化转型的指导意见》,明确提出以数据为引擎,系统性重塑城市技术架构与管理流程,推动城市治理迈向“全域协同、数实融合”的…...
Java网络编程干货
1.网络编程是什么 了解 在Java语言中,我们可以使用java.net包下的技术轻松开发出常见的网络应用程序,从而把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统&#x…...
如何在 Spring Boot 项目中使用 MyBatis 进行批量操作以提升性能?
MyBatis 提供了 ExecutorType.BATCH 类型,允许将多个 SQL 语句进行组合,最后统一执行,从而减少数据库的访问频率,提升性能。 以下是如何在 Spring Boot 项目中使用 MyBatis 进行批量操作的关键点: 1. 配置 MyBatis 使…...
基于SSM的线上花店鲜花销售商城网站系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
Python Lambda表达式详解
Python Lambda表达式详解 1. Lambda是什么? Lambda是Python中用于创建匿名函数(没有名字的函数)的关键字,核心特点是简洁。它适用于需要临时定义简单函数的场景,或直接作为参数传递给高阶函数(如map()、f…...
DAPP实战篇:使用web3.js连接合约
说明 本系列内容目录:专栏:区块链入门到放弃查看目录 如果你还没有创建好项目请先查看:《DApp实战篇:先用前端起个项目》,如果你还不知道web3.js是什么请先查看:《DApp实战篇:前端技术栈一览》。 安装 点此查看web3.js官方文档 打开项目根目录,并唤起终端: 键入w…...
linux sar 系统运行状态统计
概述 sar 命令来自英文词组**“System activity reporter”**的缩写,其功能是用于统计系统运行状态。是一个系统活动报告工具,用于收集、报告和保存系统活动信息。它可以帮助系统管理员监控和分析系统性能,识别潜在的性能瓶颈或问题。 实时…...
【C#】一种优雅的基于winform的串口通信管理
serialPort.DataReceived、串口优雅管理 完整《C#串口通信系统》功能清单 Part 1 — SerialPortManager.cs —— 串口核心管理类 using System; using System.IO.Ports; using System.Text; using System.Threading; using System.Windows.Forms;/// <summary> /// 专业…...
ChatGPT之智能驾驶问题讨论
ChatGPT之智能驾驶问题讨论 1. 源由2. 问题:2.1 智能驾驶级别定义🚗 L2(部分自动化,Partial Automation)🤖 L3(有条件自动化,Conditional Automation)🛸 L4&a…...
K8S-证书过期更新
K8S证书过期问题 K8S证书过期处理方法 Unable to connect to the server: x509: certificate has expired or is not yet valid 1、查看证书有效期: # kubeadm certs check-expiration2、备份证书 # cp -rp /etc/kubernetes /etc/kubernetes.bak3、直接重建证书 …...
蓝桥杯第十五届真题——握手问题
#include<bits/stdc.h> using namespace std; int main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int sum0;for(int i7;i<49;i){sumi;}cout<<sum;return 0; }...
5G_WiFi_CE_DFS
目录 一、规范要求 1、法规目录 2、定义 3、运行模式 4、主/从设备相关的运行行为及具体的动态频率选择(DFS)要求 5、产品角色确定测试项目 6、测试项目 测试项1:信道可用性检查(Channel Availability Check) …...
第二节:React 基础篇-受控组件 vs 非受控组件
一、场景题:设计一个实时搜索输入框,说明选择依据 受控组件 vs 非受控组件 核心区别 特征受控组件非受控组件数据管理由React状态(state)控制通过DOM元素(ref)直接访问更新时机每次输入触发onChange提交…...
springboot 处理编码的格式为opus的音频数据解决方案【java8】
opus编码的格式概念: Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由IETF(互联网工程任务组)进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用…...
RK3568 基于Gstreamer的多媒体调试记录
文章目录 1、环境介绍2、概念理清3、提前准备4、GStreamer编译5、GStreamer基础介绍6、视频播放初体验7、视频硬编码7.1、h2647.2、h265 8、视频硬解码8.1、解码视频并播放8.2、解码视频并播放带音频 1、环境介绍 硬件:飞凌ok3568-c开发板 软件:原厂rk…...
VS Code 的 .S 汇编文件里面的注释不显示绿色
1. 确认文件语言模式 打开 .S 文件后,查看 VS Code 右下角的状态栏,确认当前文件的识别模式(如 Assembly、Plain Text 等)。如果显示为 Plain Text 或其他非汇编模式: 点击状态栏中的语言模式(如 Plain Te…...
在 Wireshark 中如何筛选数据包
1. 显示过滤器(Display Filters) 显示过滤器用于 在已捕获的数据包中筛选,语法类似于编程语言中的条件表达式。 (1)基本过滤 表达式说明ip.addr 192.168.1.1显示所有涉及 192.168.1.1 的 IP 包ip.src 192.168.1.1…...


