简单多状态DP问题

news2024/11/23 8:10:28

这里写目录标题

  • 什么是多状态DP
  • 解决多状态DP问题应该怎么做?
  • 关于多状态DP问题的几道题
    • 1.按摩师
    • 2.打家劫舍Ⅱ
    • 3.删除并获得点数
    • 4.粉刷房子
    • 5.买卖股票的最佳时期含手冷冻期
  • 总结

在这里插入图片描述

什么是多状态DP

多状态动态规划(Multi-State Dynamic Programming, Multi-State DP)问题是动态规划(DP)领域中的一个高级概念,涉及到在算法设计中引入多个状态来描述和解决复杂问题。与传统的单状态DP问题相比,多状态DP问题能够处理更多维度的状态信息,以应对更复杂的决策过程和状态转移关系。

以下是对多状态DP问题的详细介绍,包括定义、特点、常见应用场景和解决方法:

  • 定义
    多状态DP问题是指在动态规划算法中,引入了多个状态变量来描述一个问题的状态空间,并在这些状态之间进行转移来优化目标函数。每个状态变量通常代表了问题的一种不同的维度或特征,共同影响最终的决策过程。

简单定义:
在多状态DP问题中,我们使用一个或多个状态变量来描述问题的当前状态,并通过状态转移方程来找到从初始状态到目标状态的最优解。

  • 特点
    状态空间多维:与单状态DP不同,多状态DP问题中包含多个状态变量,每个状态变量可以是一个离散的值或者一个连续的范围。
    状态转移复杂:状态之间的转移关系可能更加复杂,需要同时考虑多个维度的变化。
    优化目标:目标通常是最小化或最大化一个函数,这个函数依赖于多个状态变量的组合。
  • 常见应用场景
    路径规划:如在地图上寻找从起点到终点的最短路径时,可以使用多个状态来描述不同的交通模式、时间限制等。
    资源分配:如在生产计划中,考虑生产任务的时间、资源消耗、设备状态等多个因素来优化生产计划。
    游戏设计:如在游戏中模拟复杂的状态变化,如角色的技能、装备状态、关卡进展等。
    网络优化:如在网络流问题中,考虑多种流量限制、路由选择等因素来优化网络流量分配。
  • 常见问题类型
    以下是一些典型的多状态DP问题示例:
    背包问题的扩展:如多维背包问题,其中不仅需要考虑物品的重量和价值,还需要考虑物品的其他特性(例如容量、数量限制等)。
    序列比对:如生物信息学中的序列比对问题,涉及对比多个序列的不同状态(如基因序列的匹配和变异)。
    多阶段决策问题:如多阶段投资决策,其中每个阶段的决策会影响后续阶段的状态。

解决多状态DP问题应该怎么做?

解决方法
解决多状态DP问题通常包括以下几个步骤:

  1. 定义状态变量:确定问题中的所有状态变量及其可能的取值范围。
  2. 构建状态转移方程:描述从一个状态转移到另一个状态的规则,通常包括状态之间的转移条件和代价。
  3. 设定初始状态和目标状态:确定动态规划的起始状态和目标状态,以及需要优化的目标函数。
  4. 编写DP递推公式:根据状态转移方程编写DP算法的递推公式。
  5. 实现DP算法:使用编程语言实现DP算法,并进行优化以提高算法的效率。

关于多状态DP问题的几道题

1.按摩师

题目链接
问题:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题题意很简单一个按摩师,可以接收源源不断的预约请求,但是有一点他的预约请求不能在相邻的两天,意思就是我们看示例1,我们如果接受了1,那么就不能接受2,但是 可以接收3,3是可接受,但是不是一定要接受,最后让我们求预约的最长的时长的总和。
算法原理
状态表示:dp[i]表示到达i位置的最长预约时长。
状态转移方程 :这里我们想,到达i位置我们是不是有两种子状态,一种是预约,一种是不预约,如果预约话前一个i-1就不能预约,因为相邻的两个不能同时预约,所以我们将预约这种状态定义为f[i],将不预约这种状态定义为g[i],这里表示预约和不预约的最长预约时间。
所以这里第一种情况:当接受i位置的预约时,我们就不能接受i-1位置的预约,则f[i]可以表示为:f[i]=g[i-1]+nums[i]
第二种情况:当不接受i位置的值的时候,i-1位置可以选,可以不选,所以这里求选和不选的最大值,g[i]=max(g[i-1],f[i-1])
代码展示:

class Solution {
public:
    int massage(vector<int>& nums) 
    {
        if(nums.size()==0)
        {
            return 0;
        }
        //讨论两种情况,选或者不选
        int n = nums.size();
        vector<int> f(n), g(n);
        //初始化
        f[0] = nums[0], g[0] = 0;
        for (int i = 1;i < n;i++)
        {
            f[i] = g[i - 1] + nums[i];
            g[i] = max(g[i - 1], f[i - 1]);
        }
        return max(g[n - 1], f[n - 1]);
    }
};

运行结果:
在这里插入图片描述

2.打家劫舍Ⅱ

题目链接
问题:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题讲的是一个小偷,他要偷东西,但是不能偷相邻两个房间的东西,因为偷相邻两个房间的东西会触发报警器,还有一个要求就是不能同时偷头尾两个位置的东西,然后数组中的值代表房间的价值。最后让我们求可以偷到的最高价值。
算法原理:

这道题其实和打家劫舍1一样,只需要多一个判断,判断第一个位置是否偷,如果第一个位置偷,则第二个位置不能偷,如果 第一个位置不偷,则第二个位置可以偷 也可以不偷。
然后对可以偷的部分来一次打家劫舍1就可以了。
代码展示:

class Solution {
public:
    int rob(vector<int>& nums) 
    {
        int n=nums.size();
        //三种情况当中偷最大的
        if(n==1)
        {
            return nums[0];
        }
        if(n==2)
        {
            return max(nums[0],nums[1]);
        }
        if(n==3)
        {
            return max(max(nums[0],nums[1]),nums[2]);
        }
        //如果选第一个位置
        vector<int> f1(n),g1(n);
        f1[2]=nums[0]+nums[2],g1[2]=nums[0];
        for(int i=3;i<n-1;i++)
        {
            f1[i]=g1[i-1]+nums[i];
            g1[i]=max(g1[i-1],f1[i-1]);
        }
        vector<int> f2(n),g2(n);
        f2[1]=nums[1],g2[1]=0;
        for(int i=2;i<n;i++)
        {
            f2[i]=g2[i-1]+nums[i];
            g2[i]=max(g2[i-1],f2[i-1]);
        }
        return max(max(f1[n-2],g1[n-2]),max(g2[n-1],f2[n-1]));
    }
};

运行结果:
在这里插入图片描述

3.删除并获得点数

题目链接
问题:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题让我们求的是最大点数,我们先看第一个例子,如果我们选了3,我们则不能选4和2,因为4和2不满足要求。如果我们选择4,我们则不能选择3但是我们可以选择2,这样最大的点数就是6
算法原理:
先对数组进行排序,升序数组利于我们跳过,然后再创建一个辅助数组,辅助数组的大小是原数组中最大的那个数加1,这个辅助数组的用途就是 存数组中的所有的数,如果 有相同的数则相加存起来,如果没有的话,则初始化为0.
状态表示:dp[i]表示i位置的当前获得的最大点数。。
状态转移方程:这里到达i位置的时候有两种情况,选或者不选,所以我们又需要两种状态来表示,这里选f[i],不选g[i],这里如果我们选第i个位置则前后位置都不能选则f[i]=g[i-1]+arr[i]如果我们不选i位置,则i-1位置可以选也可以不选,就是求选和不选的最大值:g[i]=max(g[i-1],f[i-1])

代码展示:

class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        vector<int> arr(nums[n - 1]+1);
        for (int i = 0;i < nums.size();i++)
        {
            arr[nums[i]] += nums[i];
        }
        vector<int> f(arr.size()), g(arr.size());
        f[0] = arr[0], g[0] = 0;//f[0]=2,g[0]=0
        for (int i = 1;i < arr.size();i++)
        {
            f[i] = g[i - 1] + arr[i];
            g[i] = max(g[i - 1], f[i - 1]);
        }
        return max(g[arr.size() - 1], f[arr.size() - 1]);
    }
};

运行结果:
在这里插入图片描述

4.粉刷房子

题目链接
问题:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题首先要读懂题,这道题给出二维数组costs[i][j],i表示有多少个房子,然后j表示三种颜色,三种颜色分别是红蓝绿,但是这三种颜色 不能涂在相邻两个格子中,最后让我们求最小的花费
算法原理:
状态表示:dp[i]表示图到第i个房间的最小的花费
状态转移方程:这里由于涉及到三种颜色,这三种颜色分别是三种状态,所以这里我们开辟一个二维数组,这个二维数组的大小是n*3,0表示红色,1表示蓝色,2表示绿色。这里当我们第i个房间,这里我们先对红色进行讨论,由于第n个房间图了红色,所以我们的前一个房间就不能图红色,就只能在蓝色和绿色中选一个颜色,所以这里的最小花费应该是i-1的蓝色和绿色的最小花费中的最小的一个再加上当前位置的红色的最小花费: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]=dp[i-1][1]+dp[i-1][0])+costs[i][2]

代码展示:

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

运行结果:
在这里插入图片描述

5.买卖股票的最佳时期含手冷冻期

题目链接
问题:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题要我们求是最大的股受益,第一个示例,如果我们买入第一个股票在2的时候卖出则就不能在在3时买入,因为卖出的往后一天处于冷冻期,所以这里我们不能买入股票,冷冻期一过,我们就可以买入股票,我们在0的时候买入一支股票,然后在2的时候卖出,则最大受益就是3.
算法原理:
状态表示:dp[i]表示到达当前位置时的最大利润
状态转移方程:当我们到达i位置时,我们有三种状态,第一种状态是买入(持有股票) ,第二种状态是卖出(未持有股票),第三种状态是冷冻期(冷冻期,不能购买股票)。这三种状态我们分别用0,1,2表示,所以这里我们就可以用一个二维DP表来表示这个dp模型。
在这里插入图片描述
根据上图,我们可以得出简单的状态转移方程,dp[i][0]=max(dp[i-1][1]-prices[i],dp[i-1][0]]),dp[i][0]=max(dp[i-1][2],dp[i--1][1],dp[i][2]=dp[i-1][0]+prices[i]
代码展示:

class Solution {
public:
    int maxProfit(vector<int>& prices) 
    {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3, 0));
        //0买入状态,1可交易状态,2冷冻期
        dp[0][0] = -prices[0], dp[0][1] = 0, dp[0][2] = 0;
        for (int i = 1;i < n;i++)
        {
            dp[i][0] = max(dp[i - 1][1] - prices[i], dp[i - 1][0]);
            dp[i][1] = max(dp[i - 1][2], dp[i - 1][1]);
            dp[i][2] = dp[i - 1][0] + prices[i];
        }
        //如果最后一次交易手里还剩有股票,那么肯定不是最大的利润
        return max(dp[n - 1][1], dp[n - 1][2]);
    } 
};

运行结果:
在这里插入图片描述

总结

在本文中,我们深入探讨了多状态动态规划(DP)问题的核心概念、应用场景和解法技巧。通过分析多状态DP问题的基本结构和挑战,我们不仅回顾了经典的动态规划方法,还揭示了如何在复杂的问题中引入多个状态来实现高效求解。

从具体的算法设计到实际应用案例,我们讨论了如何构建状态转移方程、优化空间复杂度以及处理状态之间的依赖关系。这些高级技巧不仅帮助我们解决了特定的多状态DP问题,也为应对未来更为复杂的算法问题奠定了坚实的基础。

多状态DP不仅是解决动态规划问题的有力工具,更是我们在算法设计中应对多维复杂性的重要思路。通过对这一领域的深入了解,我们可以更好地应对实际问题中的挑战,并在算法竞赛、数据分析等领域中取得突破性进展。

希望本文的讨论能够激发你对多状态动态规划问题的兴趣,鼓励你进一步探索这一领域的高级技巧与创新方法。算法的世界充满了无限可能,而多状态DP问题则是我们探索这片领域的一把重要钥匙。

感谢你的阅读,希望你能从中获得新的启发与收获!

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

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

相关文章

Chapter8 透明效果——Shader入门精要学习笔记

一、基本概念 在Unity中通常使用两种方法来实现透明效果 透明度测试&#xff08;无法达到真正的半透明效果&#xff09;透明度混合&#xff08;关闭了深度写入&#xff09; 透明度测试 基本原理&#xff1a;设置一个阈值&#xff0c;只要片元的透明度小于阈值&#xff0c;就…

pandas数据分析(2)

列 执行df.columns获取DataFrame列信息&#xff1a; 如果在构造DataFrame时没有提供列名&#xff0c;那么pandas会用 从0开始的数字为列编号。我们也可以为列命名&#xff0c;和为索引命名类似&#xff1a; 同样也可以重命名列名&#xff1a; 使用df.drop删除列&#xff1a; 删…

Apple - Text Layout Programming Guide

本文翻译整理自&#xff1a;Text Layout Programming Guide&#xff08;更新日期&#xff1a;2014-02-11 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/TextLayout.html#//apple_ref/doc/uid/10000158i 文章目录 一、文本布局编程指…

小米集团25届校招留学生面试经验汇总及入职测评笔试题型分析

一、小米校招24年春招智能驾驶产品管理面试经验分享 ​ - **自我介绍**&#xff1a;准备一个精炼的自我介绍&#xff0c;突出自己的优势和适合岗位的特点。 - **项目经验**&#xff1a;详细回顾你在实习或项目中的具体角色和贡献&#xff0c;准备用成果和数据支撑。 - **行业…

【成都活动邀请函】7月6 | PowerData 数字经济-“成都“开源行!

【成都活动邀请函】7月6 | PowerData 数字经济-"成都"开源行&#xff01; 活动介绍活动信息线上直播扫码报名往期活动回顾专注数据开源&#xff0c;推动大数据发展 活动介绍 九天开出一成都&#xff0c;万户千门入画图。 自古以来&#xff0c;成都便是国家发展的重要…

为什么在重写equals方法后还要再重写hashcode方法(面试题)

接着上篇文章说到&#xff08;上篇文章地址&#xff1a;http://t.csdnimg.cn/udpsThttp://t.csdnimg.cn/udpsT&#xff09;我们在代码中发现重写了equals方法后还需要重写hashcode方法&#xff0c;为什么呢&#xff1f; 对于set这种数据类型&#xff0c;里面的值是不允许有重复…

【游戏引擎之路】登神长阶(五)

5月20日-6月4日&#xff1a;攻克2D物理引擎。 6月4日-6月13日&#xff1a;攻克《3D数学基础》。 6月13日-6月20日&#xff1a;攻克《3D图形教程》。 6月21日-6月22日&#xff1a;攻克《Raycasting游戏教程》。 6月23日-6月30日&#xff1a;攻克《Windows游戏编程大师技巧》。 …

【WPF】Windows系统桌面应用程序编程开发新手入门-打造自己的小工具

电脑Windows系统上的桌面程序通常是用Visual Studio 开发工具编写出来的&#xff0c;有两种开发方式供选择&#xff0c;一种是WindowForm&#xff0c;简称WinForm&#xff0c;另一种是Windows Presentation Foundation&#xff0c;简称WPF&#xff0c;这里将学习WPF项目。 文章…

安全不“放假”!暑期安全老师就用秒报小程序提示学生的安全

随着暑假的到来&#xff0c;孩子们如同出笼的小鸟&#xff0c;迫不及待地投入到广阔天地的怀抱。然而&#xff0c;作为老师&#xff0c;我深知这段时间虽然孩子们得到了放松和游玩的机会&#xff0c;但安全问题却不容忽视。如何让孩子们在享受假期的同时&#xff0c;又能确保他…

SpringBoot(一)创建一个简单的SpringBoot工程

Spring框架常用注解简单介绍 SpringMVC常用注解简单介绍 SpringBoot&#xff08;一&#xff09;创建一个简单的SpringBoot工程 SpringBoot&#xff08;二&#xff09;SpringBoot多环境配置 SpringBoot&#xff08;三&#xff09;SpringBoot整合MyBatis SpringBoot&#xff08;四…

FairGuard游戏加固无缝兼容 Android 15 预览版

2024年6月25日&#xff0c;谷歌发布了 Android 15 Beta 3 &#xff0c;作为Android 15 “平台稳定性”的里程碑版本&#xff0c;谷歌建议所有应用、游戏、SDK、库和游戏引擎开发者都将“平台稳定性”里程碑版本作为规划最终兼容性测试和公开发布的目标。 安卓开发者博客提供的版…

PostgreSQL安装教程及文件介绍

Ubuntu 安装和配置 PostgreSQL 以 Ubuntu Server 20.04&#xff0c;PostgreSQL 12 版本为例。 1. 安装 使用如下命令&#xff0c;安装指定版本的 PostgreSQL sudo apt install postgresql-12在 Ubuntu 20.04 中安装 PostgreSQL 登录您的 Ubuntu 系统并使用以下 apt 命令更新…

[HBM] HBM TSV (Through Silicon Via) 结构与工艺

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 全文 3300 字。 1 概念 1.1 什么是HBM TSV 使用 TSV 堆叠多个DDR DRAM成为一块HBM, 成倍提高了存储器位宽&#xff0c; 一条位宽相当于高速公路的一条车道&#xff0c; 车道越多&#xff…

npm安装依赖报错——npm ERR gyp verb cli的解决方法

1. 问题描述 1.1 npm安装依赖报错——npm ERR! gyp verb cli 登录后复制 npm MARN deprecated axiosQ0.18.1: critical security vuLnerability fixed in v0.21.1. For more information, npm WARN deprecated svg001.3.2: This SVGO version is no Longer supported. upgrade …

汽车电子工程师入门系列——汽车操作系统架构学习研究-AUTOSAR

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

6-14题连接 - 高频 SQL 50 题基础版

目录 1. 相关知识点2. 例子2.6. 使用唯一标识码替换员工ID2.7- 产品销售分析 I2.8 - 进店却未进行过交易的顾客2.9 - 上升的温度2.10 - 每台机器的进程平均运行时间2.11- 员工奖金2.12-学生们参加各科测试的次数2.13-至少有5名直接下属的经理2.14 - 确认率 1. 相关知识点 left …

5 数字滤波器的基本结构

目录 系统框图表示法 系统框图求系统函数 系统框图的其他结构形式 IIR数字滤波器的基本结构 直接型系统框图 级联型系统框图 并联型系统框图 信号流图 信号流图表示法 信号流图代数运算基本规则 系统框图表示法 系统框图求系统函数 系统框图的其他结构形式 IIR数字滤…

30分钟学习如何搭建扩散模型的运行环境【pytorch版】【B站视频教程】【解决环境搭建问题】

30分钟学习如何搭建扩散模型的运行环境【B站视频教程】【解决环境搭建问题】 动手学习扩散模型 点击以下链接即可进入学习&#xff1a; B站视频教程附赠&#xff1a;环境配置安装&#xff08;配套讲解文档&#xff09; 视频 讲解主要内容 一、环境设置 1.本地安装&#xf…

grpc学习golang版( 二、入门示例 )

系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、环境二、编写protobuf文件三、编写server服务端四、编写Clie…

SpringBoot入门实战:SpringBoot整合SpringSecurity

1.背景介绍 SpringBoot是Spring官方推出的一款快速开发框架&#xff0c;它基于Spring框架&#xff0c;采用了约定大于配置的开发方式&#xff0c;简化了开发过程&#xff0c;提高了开发效率。SpringBoot整合SpringSecurity是SpringBoot与SpringSecurity的集成&#xff0c;可以实…