【动态规划】简单多状态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,一经查实,立即删除!

相关文章

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

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

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

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

如何在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搭建一…

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

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

ULTRAINTERACT 数据集与 EURUS 模型:推动开源大型语言模型在推理领域的新进展

在人工智能的浪潮中&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已经成为推动自然语言处理技术发展的关键力量。它们在理解、生成语言以及执行复杂任务方面展现出了巨大的潜力。然而&#xff0c;尽管在特定领域内取得了显著进展&#xff0c;现有的开源LLMs在处理多样…

Vue3+ElementPlus+pinia 小案例

Vue3ElementPluspinia 小案例 1、初始化项目 使用脚手架快速创建Vue3应用&#xff1a;https://cli.vuejs.org/zh/ 脚手架自动整合了vue-router路由、ts、前端工程化等库&#xff1b; 安装脚手架工具 npm install -g vue/cli检测安装是否成功 vue -V创建项目&#xff1a; …

UnityShader——基础篇之UnityShader基础

UnityShader基础 UnityShader概述 材质和UnityShader 总的来说&#xff0c;在Unity中需要配合使用材质(Material)和 Unity Shader 才能达到需要的效果&#xff0c;常见流程为&#xff1a; 创建一个材质创建一个 Unity Shader&#xff0c;并把它赋给上一步中创建的材质把材质…

Android模拟器linux内核的下载,编译,运行,驱动开发测试

Android模拟器linux内核的下载&#xff0c;编译&#xff0c;运行&#xff0c;内核模块开发 1.下载适合Android模拟器的内核 git clone https://aosp.tuna.tsinghua.edu.cn/android/kernel/goldfish.git git branch -a git checkout android-goldfish-4.14-gchips 新建一个目录…

【2024最新版】Java JDK安装配置全攻略:图文详解

目录 1. 引言2. 准备工作2.1 **确定操作系统**2.2 **检查系统要求**2.3 **下载JDK安装包**3. 安装步骤&#xff08;以Windows系统为例&#xff09;4. 配置环境变量4.1 jdk配置验证4.2 **配置JAVA_HOME环境变量**4.3 **配置Path环境变量**4.4 验证jdk是否配置成功 5. 结语 1. 引…

机器学习周记(第四十四周:Robformer)2024.6.17~2024.6.23

目录 摘要ABSTRACT1 论文信息1.1 论文标题1.2 论文摘要1.3 论文引言1.4 论文贡献 2 论文模型2.1 问题描述2.2 Robformer2.2.1 Encoder2.2.2 Decoder 2.3 鲁棒序列分解模块2.4 季节性成分调整模块 摘要 本周阅读了一篇利用改进 Transformer 进行长时间序列预测的论文。论文模型…

浅析MySQL-基础篇01

目录 执行一条select语句&#xff0c;发生了什么&#xff1f; MYSQL执行流程是怎么样的&#xff1f; 第一步&#xff1a;连接器 第二步&#xff1a;查询缓存 第三步&#xff1a;解析SQL 解析器 第四步&#xff1a;执行SQL 预处理器 优化器 执行器 执行一条select语句…