【动态规划】简单多状态dp问题

一、经验总结

在分析dp问题的状态表示时,发现当前阶段的状态可以继续细分为多个状态,且多个状态之间可以通过某种方式进行转换,这就是动态规划的多状态问题。

多状态问题的关键有以下几点:

  1. 找出dp问题的多个状态表示:经验+题目要求,在之前经验的基础上(以i位置为起点或终点)继续对当前阶段的状态进行细分。为每种状态各自创建出一个dp表。每种状态可能还有若干子状态,此时应该为每种状态的dp表增加维度,以表示出所有的子状态。

  2. 确定多个状态间的相互转换关系:对于简单题目可以直接得到转换关系(前4题);但是如果每个阶段的状态数量较多,状态间的相互转换较为复杂,可以借助状态机模型分析各状态间的转换关系(后4题),其中:

    1. 各顶点表示的是每个阶段的各种状态(在第一步确定状态表示时得出)
    2. 箭头的起点是前一阶段的状态
    3. 箭头的终点是当前阶段的状态
    4. 箭头上的动作是状态转换时需要进行的活动(当前阶段)

    如何绘制状态机?

    1. 先画出每个阶段的各种状态
    2. 对于每种状态,先考虑自己能不能转换为自己(状态不改变)
    3. 再考虑其他状态能不能转换为该状态
    4. 标出状态转换时需要进行的活动(也可以啥也不干)
  3. 之后就可以依据转换关系写出各种状态的状态转移方程了。最好依据绘制状态机的顺序写方程,做到不重不漏的计算出所有状态的结果。

  4. 填表顺序:要按照顺序将创建的多个dp表一起填

  5. 返回值:要考虑到所有的状态


二、相关编程题

2.1 按摩师

题目链接

面试题 17.16. 按摩师 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int massage(vector<int>& nums) {//1.创建dp表//2.初始化//3.填表//4.返回值int n = nums.size();if(n == 0) return 0;vector<int> dp1(n), dp2(n);dp1[0] = nums[0];for(int i = 1; i < n; ++i){dp1[i] = dp2[i-1] + nums[i];dp2[i] = max(dp1[i-1], dp2[i-1]);}return max(dp1[n-1], dp2[n-1]);}
};

2.2 打家劫舍Ⅱ

题目链接

LCR 090. 打家劫舍 II - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();return max(rob1(nums, 2, n-1) + nums[0], rob1(nums, 1, n));}int rob1(vector<int>& nums, int begin, int end) {if(begin >= end) return 0;int n = end-begin; //左闭右开vector<int> dp1(n), dp2(n); //dp1偷/dp2不偷dp1[0] = nums[begin];for(int i = 1; i < n; ++i){dp1[i] = dp2[i-1] + nums[begin+i]; //注意下标映射关系dp2[i] = max(dp1[i-1], dp2[i-1]);}return max(dp1[n-1], dp2[n-1]);}
};

2.3 删除并获得点数

题目链接

740. 删除并获得点数 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int deleteAndEarn(vector<int>& nums) {const int N = 10001;int arr[N] = {0}; //该数组用于统计每个数字出现的总和for(auto e : nums)arr[e]+=e;vector<int> dp1(N), dp2(N); //dp1获取,dp2不获取dp1[1] = arr[1];for(int i = 2; i < N; ++i){dp1[i] = dp2[i-1]+arr[i];dp2[i] = max(dp1[i-1], dp2[i-1]);}return max(dp1[N-1], dp2[N-1]);}
};

2.4 粉刷房子

题目链接

LCR 091. 粉刷房子 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int minCost(vector<vector<int>>& costs) {int n = costs.size();vector<vector<int>> dp(n+1, vector<int>(3));for(int i = 1; i <= n; ++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][1], dp[i-1][0])+costs[i-1][2];}return min(dp[n][0], min(dp[n][1], dp[n][2]));}
};

2.5 买卖股票的最佳时机含冷冻期

题目链接

309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

如果每个阶段的状态数量较多,状态间的相互转换较为复杂,可以借助状态机模型分析各状态间的转换关系,其中:

  1. 各顶点表示的是每个阶段的各种状态(在第一步确定状态表示时得出)
  2. 箭头的起点是前一阶段的状态
  3. 箭头的终点是当前阶段的状态
  4. 箭头上的动作是状态转换时需要进行的活动(当前阶段)

如何绘制状态机?

  1. 先画出每个阶段的各种状态
  2. 对于每种状态,先考虑自己能不能转换为自己(状态不改变)
  3. 再考虑其他状态能不能转换为该状态
  4. 标出状态转换时需要进行的活动

编写代码

class Solution {
public:int maxProfit(vector<int>& p) {int n = p.size();vector<vector<int>> dp(n, vector<int>(3));dp[0][0] = -p[0];for(int i = 1; i < n; ++i){dp[i][0] = max(dp[i-1][0], dp[i-1][1]-p[i]);dp[i][1] = max(dp[i-1][1], dp[i-1][2]);dp[i][2] = dp[i-1][0]+p[i];}return max(dp[n-1][1], dp[n-1][2]);}
};

2.6 买卖股票的最佳时机含手续费

题目链接

714. 买卖股票的最佳时机含手续费 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int maxProfit(vector<int>& prices, int fee) {int n = prices.size();vector<int> f(n), g(n); //f是买入状态,g是可交易状态f[0] = -prices[0];for(int i = 1; i < n; ++i){f[i] = max(f[i-1], g[i-1]-prices[i]);g[i] = max(g[i-1], f[i-1]+prices[i]-fee);}return g[n-1]; //f[n-1]最后一天还有股票没有卖出,一定不是最大利润,不考虑}
};

2.7 买卖股票的最佳时机III

题目链接

123. 买卖股票的最佳时机 III - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

为什么INF(无穷大)用0x3f3f3f3f表示?请阅读文章:0x3f3f3f3f是什么意思-CSDN博客

用0x3f3f3f3f表示32-bit int最大值的好处:

  1. 足够大:0x3f3f3f3f是10^9级别的,比一般场合下的数据都要大,所以它可以作为无穷大使用,而不至于出现数据大于无穷大的情况。
  2. 加数据不会溢出:0x3f3f3f3f加上一个数据时并不会溢出,也就是说“无穷大加上一个有穷的数依然是无穷大”。甚至0x3f3f3f3f + 0x3f3f3f3f依然没有超过32-bit int的表示范围,也就满足了我们“无穷大加无穷大还是无穷大的需求”。
  3. 可以使用memset设置内存:之前如果我们要将某个int数组全部赋值为INT_MAX,需要自己写循环,不能使用memset,因为memset是以字节为单位进行赋值的。现在好了,如果我们将无穷大设为0x3f3f3f3f,由于它的每个字节都是0x3f,我们可以通过memset(arr, 0x3f, sizeof(arr));将数组全部置为无穷大。

编写代码

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();int INF = 0x3f3f3f3f; //无穷大vector<vector<int>> f(n, vector<int>(3, -INF)), g(n, vector<int>(3, -INF));//边界1:第0天第0次交易,其余交易次数的收益初始化为-∞f[0][0] = -prices[0];g[0][0] = 0;for(int i = 1; i < n; ++i){for(int j = 0; j < 3; ++j){f[i][j] = max(f[i-1][j], g[i-1][j]-prices[i]);//边界2:第0次交易时卖出状态if(j == 0) g[i][j] = 0;elseg[i][j] = max(g[i-1][j], f[i-1][j-1]+prices[i]);}}   return max(g[n-1][0], max(g[n-1][1], g[n-1][2]));}
};

2.8 买卖股票的最佳时机Ⅳ

题目链接

188. 买卖股票的最佳时机 IV - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:int maxProfit(int k, vector<int>& prices) {int n = prices.size();k = min(k, n/2); //n天最多进行n/2次有效交易const int INF = 0x3f3f3f3f;vector<vector<int>> f(n, vector<int>(k+1, -INF));auto g = f;f[0][0] = -prices[0];g[0][0] = 0;for(int i = 1; i < n; ++i){for(int j = 0; j <= k; ++j){f[i][j] = max(f[i-1][j], g[i-1][j]-prices[i]);if(j == 0)g[i][j] = 0;elseg[i][j] = max(g[i-1][j], f[i-1][j-1]+prices[i]);}}int ret = -INF;for(int j = 0; j <= k; ++j){ret = max(ret, g[n-1][j]);}return ret;}
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8主干网络使用FasterNet替换

1 提出问题 减少GFLOPs就一定能提高模型的运行速度吗?一般人认为这个是理由应当的。但是在FasterNet文章中,作者告诉我们:不一定! 延迟与浮点数运算的关系如下: Latency=FLOPsFLOPS FLOPs:模型浮点数运算 FLOPS:每秒浮点数运算 这个你们在实验中可以得到验证,MobileN…

开源与在线 M3U8 Downloader 项目介绍及使用指南

M3U8 是一种用于播放列表格式的文件类型&#xff0c;广泛应用于流媒体服务中&#xff0c;特别是 HLS&#xff08;HTTP Live Streaming&#xff09;协议。它包含了一系列的 TS&#xff08;Transport Stream&#xff09;视频片段地址&#xff0c;使得视频能够分段加载&#xff0c…

【深度学习驱动流体力学】湍流仿真到深度学习湍流预测

目录 一、湍流项目结构二、三个OpenFOAM湍流算例1. motorBike背景和目的文件结构和关键文件使用和应用湍流仿真深度学习湍流预测深度学习湍流预测的挑战和应用结合湍流仿真与深度学习2. pitzDaily背景和目的文件结构和关键文件使用和应用3. pitzDailyMapped背景和目的文件结构和…

说说 golang 中的接口和反射

1、接口 1.1 类型 Golang 中的接口是一组方法的签名&#xff0c;是实现多态和反射的基础。 type 接口名 interface {method1(参数列表) 返回值列表method2(参数列表) 返回值列表 }不同于 Java 语言&#xff0c;使用 implements 关键字显示的实现接口。Golang 接口的实现都是…

【服务器06】之【如何不开外网连接GitHub】

登录GitHub官网 GitHub: Let’s build from here GitHub 注册账号 登录账号 输入一个自定义名字&#xff0c;点击创建存储库就可以了 首先 如何在不开外网的条件下使用GitHub 第一步 下载安装Steam(Watt TooklKit) 区分一下如何查看哪个官网&#xff08;没有百度广告就是…

实时导航 C语言

实现实时导航的一种方法是使用C语言和一些外部库&#xff0c;如SDL&#xff08;Simple DirectMedia Layer&#xff09;来处理图形界面和输入&#xff0c;以及OpenGL进行图形渲染。以下是一个简单的例子&#xff0c;展示了如何使用C语言和SDL库来创建一个简单的实时导航应用。 …

Package libcudnn8 is not installed.的问题

ubantu20.04&#xff0c;cuda11.2安装cuda&#xff0c; cudann . 安装CUDNN时&#xff0c;如果选择 Deb安装方法&#xff0c; 有三个安装包要安装&#xff0c;必须先安装runtime版本&#xff0c;再安装developer版本&#xff0c;不然就会出现以下问题&#xff1a; dpkg: depe…

如何在Android中实现多线程与线程池?

目录 一、Android介绍二、什么是多线程三、什么是线程池四、如何在Android中实现多线程与线程池 一、Android介绍 Android是一种基于Linux内核的开源操作系统&#xff0c;由Google公司领导开发。它最初于2007年发布&#xff0c;旨在为移动设备提供一种统一、可扩展的操作系统。…

UltraEditUEStudio软件安装包下载及安装教程

​根据软件大数据显示提供预定义的或使用者创建的编辑“环境”&#xff0c;能记住 UltraEdit 的所有可停靠窗口、工具栏等的状态。实际上我们可以这样讲HTML 工具栏&#xff0c;对常用的 HTML 功能作了预配置;文件加密/解密;多字节和集成的 IME。根据使用者情况表明Git Editor&…

【Linux基础IO】磁盘的结构、文件系统与inode、软硬链接

目录 磁盘的物理存储结构 磁盘的逻辑结构 文件系统与inode 硬链接 软链接 关于目录文件 磁盘的物理存储结构 磁盘是计算机中唯一的机械硬件设备&#xff0c;由磁头&#xff0c;盘面&#xff0c;磁道&#xff0c;扇区这四部分对磁盘上的数据进行增删查改操作。盘面上存储的…

面向对象修炼手册(二)(消息与继承)(Java宝典)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;面向对象修炼手册 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 消息传递 1 基本概念 1.…

App推广告别邀请码,Xinstall助您一键触达海量用户!

在移动互联网高速发展的今天&#xff0c;App的推广与运营已成为每个开发者都必须面对的问题。然而&#xff0c;随着互联网流量的日益分散和用户需求的不断变化&#xff0c;传统的App推广方式已经难以满足现代市场的需求。尤其是在获取用户时&#xff0c;很多开发者还在采用传统…

动手学深度学习(Pytorch版)代码实践 -卷积神经网络-26网络中的网络NiN

26网络中的网络NiN import torch from torch import nn import liliPytorch as lp import matplotlib.pyplot as plt# 定义一个NiN块 def nin_block(in_channels, out_channels, kernel_size, strides, padding):return nn.Sequential(# 传统的卷积层nn.Conv2d(in_channels, ou…

图的学习.

目录 一、图的基本概念 1.1图的种类 1.2顶点的度、入度和出度 1.3边的权和网 1.4路径、路径长度和回路 二、图的存储结构 2.1邻接矩阵法 2.2邻接表法 2.3十字链表 2.4邻接多重表 三、图的遍历 3.1广度优先搜索 3.2深度优先搜索 四、图的应用 4.1最小生成树 4.1.…

VSCode 安装Remote-SSH

1、打开扩展商店安装Remote-SSH 快捷键&#xff1a;CtrlShiftX 2、配置ssh连接 打开命令面板&#xff08;CtrlShiftP&#xff09; 输入"Remote-SSH: Connect to Host"并选择。 输入你的Ubuntu服务器的IP地址或主机名。 3、连接到ubuntu服务器 如果是第一次连接&…

FPGA结构相关简介

一、芯片分类 ​FPGA属于数字芯片的一种&#xff0c;下面是根据世界半导体贸易统计协会WSTS的一个半导体分类&#xff0c;可以看到FPGA所属的类别。 二、FPGA的发展史 ​下图为FPGA的发展历史 三、FPGA的结构分类 下面是从三个角度进行划分 四、参考资料 《FPGA原理与结构》—…

【课程总结】Day10:卷积网络的基本组件

前言 由于接下来的课程内容将围绕计算机视觉展开&#xff0c;其中接触最多的内容是卷积、卷积神经网络等…因此&#xff0c;本篇内容将从卷积入手&#xff0c;梳理理解&#xff1a;卷积的意义、卷积在图像处理中的作用以及卷积神经网络的概念&#xff0c;最后利用pytorch搭建一…

1169 正方形

简单- 时间限制&#xff1a; 1000MS内存限制&#xff1a; 256MB分数&#xff1a;100OI排行榜得分&#xff1a;10(0.1*分数2*难度) 考点&#xff1a;选择结构 描述 有一个正方形&#xff0c;四个角的坐标分别是&#xff08;1&#xff0c;-1&#xff09;&#xff0c;&#xff…

proactor模式

Proactor模式是一种异步I/O的设计模式&#xff0c;它允许程序直接发起一个异步I/O操作并立即返回&#xff0c;而不需要等待该操作完成。一旦I/O操作实际完成&#xff0c;系统会通知相应的完成处理程序&#xff08;Completion Handler&#xff09;&#xff0c;该处理程序随后执行…

构建未来应用的核心,云原生技术栈解析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、云原生技术栈 1、容器和容器编排 1.1 Docker 1.2 Kubernete…