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

news2025/7/17 2:46:21


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥

✨✨✨✨✨✨ 个人主页✨✨✨✨✨✨

        在前面的博客中,我们已经练习了很多动态规划类型的题目,但是前面的动态规划仅仅是单独状态的,今天这一篇博客我们一起来探索一下简单多状态动态规划类型的题目~准备好了吗~我们发车去探索奥秘啦~🚗🚗🚗🚗🚗🚗

目录

按摩师(打家劫舍)

打家劫舍Ⅱ

删除并获得点数


按摩师(打家劫舍)

按摩师(打家劫舍)

        前面已经提到了这是一种简单多状态的dp问题,那么这个多状态体现在哪里呢?题目要求不可以接受相邻的预约,那么就说明每一个位置的状态可能是选择的,也可能是没有选择的~这就有两个状态了,那么有两个状态我们应该怎么表示呢?我们可以创建两个dp表,接下来我们结合前面的思想来分析一下这道多状态问题~

分析:

1、状态表示

题目要求:不可以接受相邻的预约,那么每一个预约有选择和不选择这两种状态~我们创建两个dp表来进行表示

        结合这里的题目要求+经验:

        dp1中的dp1[i]表示为到达该位置并且选择该位置预约的最长预约时间~

        dp2中的dp2[i]表示为到达该位置并且不选择该位置预约的最长预约时间~

2、状态转移方程

       我们以离【i】位置最近的状态分析状态转移方程,处理两个dp表

1、dp1【i】选择【i】位置,那么说明前面的位置是一定不可以选择的,那么dp1[i]=dp2[i-1]+nums[i]

2、dp2【i】不选择【i】位置,那么说明前面的位置可以选择、也可以不选择,取两者的最大值~那么dp2[i]=max(dp1[i-1],dp2[i-1]

3、初始化

        我们可以看到,状态转移方程里面有i-1当i=0的时候显然会出现越界的情况,所以我们需要进行初始化

        结合前面如果不想初始化太麻烦,我们可以多申请一些空间,但是事实上这个题目初始化比较简单,直接初始化dp1[0],dp2[0]就可以了,所以我们直接进行初始化~

        dp1[0]就是选择0位置预约, dp2[0]就是不选择0位置预约,那么我们初始化结果就是

                dp1[0]=nums[0],dp2[0]=0

4、填表顺序

        我们这里的逻辑是从前面依次推出后面的,所以填表顺序是从前往后

5、返回结果

      这里返回结果是最后一个位置,最后一个位置有两种情况,一种是选择最后一个位置,一种是不选择最后一个位置,返回两种情况最大值就可以了,即返回max(dp1[n-1],dp2[n-1])

注意点:这里需要处理一下元素个数为0的边界情况

有了前面的分析,代码实现就比较简单了~

代码实现:

class Solution 
{
public:
    int massage(vector<int>& nums) 
    {
        //1、创建两个dp表
        int n=nums.size();
        //处理边界情况
        if(n==0) return 0;
        vector<int> dp1(n);
        vector<int> dp2(n);

        //2、初始化
        dp1[0]=nums[0];
        dp2[0]=0;

        //3、填表
        for(int i=1;i<n;i++)
        {
            dp1[i]=dp2[i-1]+nums[i];
            dp2[i]=max(dp1[i-1],dp2[i-1]);
        }

        //4、返回结果
        return max(dp1[n-1],dp2[n-1]);
    }
};

顺利通过~

打家劫舍Ⅱ

打家劫舍Ⅱ

        这个题目和上一道题目是十分类似的,不过题目多了头尾不能同时选择的条件~那么我们是不是就可以根据【0】位置是否选择来进行区分:

        1、选择【0】位置,显然【1】位置和【n-1】位置都不能进行选择了,但是在【2】~【n-2】这个区间内,我们不就可以随便选择了吗~也就可以使用前面我们打家劫舍的思路了~

        2、不选择【0】位置,显然【1】位置和【n-1】位置都能进行选择,那么在【1】~【n-1】这个区间内,我们就可以随便选择~也就可以使用前面我们打家劫舍的思路了~

这个题目与前面的分析高度类似,就不进行重复分析了~

优化:我们可以把打家劫舍的代码优化成一个函数进行调用~

我们来看看代码实现:

class Solution 
{
public:
    //打家劫舍一
    int rob1(vector<int>& nums,int left,int right)
    {
        if(left>right) return 0;//处理不合法情况
        //也就处理了边界情况
        //1、创建两个dp表
        //vector<int> dp1(right-left+1);
        //vector<int> dp2(right-left+1);
        //优化:减少映射关系处理,直接申请n个大小空间
        int n=nums.size();
        vector<int> dp1(n);
        vector<int> dp2(n);
        //2、初始化
        dp1[left]=nums[left];
        dp2[left]=0;
        //3、填表
        //注意填表范围和顺序
        for(int i=left+1;i<=right;i++)
        {
            dp1[i]=dp2[i-1]+nums[i];
            dp2[i]=max(dp1[i-1],dp2[i-1]);
        }
        //4、返回结果
        //注意返回位置
        return max(dp1[right],dp2[right]);
    }
    int rob(vector<int>& nums) 
    {
        int n=nums.size();
        return max(nums[0]+rob1(nums,2,n-2),0+rob1(nums,1,n-1));
    }
};

顺利通过~

删除并获得点数

删除并获得点数

        这个题目看起来有点难,看题目要求相邻的两个数是不可以同时存在的,这个不就与我们的打家劫舍类似嘛?那么我们怎么将这个题目与打家劫舍联系起来呢?这里是数不能相邻,那么我们就可以把每一个数的累加和保存到一个数组中,利用数组下标就可以找到他~同时数组下标是相邻的,再对这个数组用一次打家劫舍的思想就可以~

        这个题目与前面的动态规划分析高度类似,就不进行重复分析了~

代码实现:

class Solution
{
public:
    int deleteAndEarn(vector<int>& nums)
    {
        //预处理
        //问题转化
        int n = nums.size();
        int m = 0;//不要用max命名,容易与算法库max混淆
        for (auto e : nums)
        {
            if (e > m)
                m = e;
        }
        vector<int> arr(m + 1);//根据最大数据开辟空间
        for (auto e : nums)
        {
            arr[e] += e;//统计数据和
        }
        //动态规划
        //1、创建两个dp表
        vector<int> dp1(m + 1);
        vector<int> dp2(m + 1);
        //2、初始化
        dp1[0] = arr[0], dp2[0] = 0;
        //3、填表
        for (int i = 1; i < m + 1; i++)
        {
            dp1[i] = dp2[i - 1] + arr[i];
            dp2[i] = max(dp1[i - 1], dp2[i - 1]);
        }
        //4、返回结果
        return max(dp1[m], dp2[m]);
    }
};

        顺利通过~

        事实上,我们这里还可以进一步优化,题目给出了数据范围,那我直接创建一个跟最大数据一样的数组就好~

class Solution
{
public:
    //优化版
    int deleteAndEarn(vector<int>& nums)
    {
        //1、预处理
        const int N = 10001;//更加方便写
        vector<int> arr(N);
        for (auto e : nums)
            arr[e] += e;
        //2、动态规划
        vector<int> dp1(N);
        vector<int> dp2(N);

        dp1[0] = arr[0];
        dp2[0] = 0;

        for (int i = 1; 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]);
    }
};

        顺利通过~

        当然,还可以进一步优化,如果只有几个数,动态表开辟那么大的空间,还是有点浪费的,我们可以把前面两个方法结合一下~

        最终版:

class Solution
{
public:
    //最终版
    int deleteAndEarn(vector<int>& nums)
    {
        //1、预处理
        const int N = 10001;//更加方便写
        int m = 0;
        vector<int> arr(N);
        for (auto e : nums)
        {
            arr[e] += e;
            m = max(m, e);
            //统计数据和的同时找数组最大值
        }
        //2、动态规划
        vector<int> dp1(m + 1);
        vector<int> dp2(m + 1);

        dp1[0] = arr[0];
        dp2[0] = 0;

        for (int i = 1; i < m + 1; i++)
        {
            dp1[i] = dp2[i - 1] + arr[i];
            dp2[i] = max(dp1[i - 1], dp2[i - 1]);
        }

        return max(dp1[m], dp2[m]);
    }
};

顺利通过~


♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨


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

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

相关文章

uniapp离线打包提示未添加videoplayer模块

uniapp中使用到video标签&#xff0c;但是离线打包放到安卓工程中&#xff0c;运行到真机中时提示如下&#xff1a; 解决方案&#xff1a; 1、把media-release.aar、weex_videoplayer-release.aar放到工程的libs目录下; 文档&#xff1a;https://nativesupport.dcloud.net.cn/…

机器人零位标定修正流程介绍

如果想看运动学标定可以看看 机器人运动学参数标定, 一次性把运动学参数和零位标定等一起标定求解. 1. 零位标定 零位标定是机器人运动学标定中的一个重要步骤&#xff0c;其目的是校正机器人关节的初始位置误差。以下是需要进行零位标定的主要原因&#xff1a; 制造误差 在机…

深入 C++ 线程库:从创建到同步的探索之旅

目录 创建多线程 获取线程返回值 1.传指针 2.传引用 原子操作 互斥量 互斥量&#xff08;Mutex&#xff09;的基本概念 mutex类型介绍 锁的类型 互斥锁&#xff08;Mutex&#xff09; 自旋锁&#xff08;Spin Lock&#xff09; 读写锁&#xff08;Read - Write Lo…

【2025年认证杯数学中国数学建模网络挑战赛】A题 解题建模过程与模型代码(基于matlab)

目录 【2025年认证杯数学建模挑战赛】A题解题建模过程与模型代码&#xff08;基于matlab&#xff09;A题 小行星轨迹预测解题思路第一问模型与求解第二问模型与求解 【2025年认证杯数学建模挑战赛】A题 解题建模过程与模型代码&#xff08;基于matlab&#xff09; A题 小行星轨…

Matlab 分数阶PID控制永磁同步电机

1、内容简介 Matlab 203-分数阶PID控制永磁同步电机 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

4185 费马小定理求逆元

4185 费马小定理求逆元 ⭐️难度&#xff1a;简单 &#x1f31f;考点&#xff1a;费马小定理 &#x1f4d6; &#x1f4da; import java.util.Scanner; import java.util.Arrays;public class Main {static int[][] a;public static void main(String[] args) {Scanner sc …

界面控件DevExpress WinForms v25.1新功能预览 - 聚焦用户体验升级

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…

卷积神经网络(CNN)基础

目录 一、应用场景 二、卷积神经网络的结构 1. 输入层&#xff08;Input Layer&#xff09; 2. 卷积层&#xff08;Convolutional Layer&#xff09; 3. 池化层&#xff08;Pooling Layer&#xff09; 最大池化&#xff08;max_pooling&#xff09;或平均池化&#xff08;…

Android Spotify-v9.0.36.443-arm64-Experimental Merged版

Android Spotify 链接&#xff1a;https://pan.xunlei.com/s/VONXTdIv9d4FnAiNMMliIAEJA1?pwdxt7q# Android Spotify-v9.0.36.443-arm64-Experimental Merged版 享受高达256kbps的AAC音频。

LLM之Agent(十六)| MCP已“过时”?Google近期推出Agent2Agent 协议 (A2A)

如今&#xff0c;企业越来越多地构建和部署自主代理&#xff0c;以帮助扩展、自动化和增强整个工作场所的流程 - 从订购新笔记本电脑到协助客户服务代表&#xff0c;再到协助供应链规划。 为了最大限度地发挥代理 AI 的优势&#xff0c;这些代理能够在一个动态的、多代理的生态…

Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification

Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification 目录 Transformer 训练:AutoModelForCausalLM,AutoModelForSequenceClassification`AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)`功能概述参数解释`AutoModelForSequen…

Java学习总结-端口-协议

端口号&#xff1a;一个16位的二进制&#xff0c;范围是0-65535 端口分类&#xff1a; 周知端口&#xff1a;0-1023&#xff0c;被预先定义的知名应用占用&#xff08;如&#xff1a;HTTP占用80&#xff0c;FTP占用21&#xff09; 注册端口&#xff1a;1024-49151&#xff0…

克魔助手(Kemob)安装与注册完整教程 - Windows/macOS双平台指南

iOS设备管理工具克魔助手便携版使用全指南 前言&#xff1a;为什么需要专业的iOS管理工具 在iOS开发和设备管理过程中&#xff0c;开发者经常需要突破系统限制&#xff0c;实现更深层次的控制和调试。本文将详细介绍一款实用的便携式工具的使用方法&#xff0c;帮助开发者快速…

qwen-vl 实现OCR的测试

OCR 技术是数字化时代必不可少的实用工具。以前都依赖专业的公司的专业软件才能完成。成本很高。也正因为如此&#xff0c;我国纸质资料的数字化并不普及。基于大模型的ORC 也许会改变这样的现状。 文本识别&#xff0c;也称为光学字符识别 (OCR)&#xff0c;可以将印刷文本或…

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

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

SVMSPro分布式综合安防管理平台-->以S3存储革新,开启智能安防新纪元

SVMSPro分布式综合安防管理平台–>以S3存储革新&#xff0c;开启智能安防新纪元 在数字化转型浪潮下&#xff0c;企业安防管理正面临海量数据存储、跨区域协同以及数据安全的严峻挑战。如何实现高效、弹性、低成本的存储扩容&#xff1f;如何确保关键录像数据万无一失&…

脑科学与人工智能的交叉:未来智能科技的前沿与机遇

引言 随着科技的迅猛发展&#xff0c;脑科学与人工智能&#xff08;AI&#xff09;这两个看似独立的领域正在发生深刻的交汇。脑机接口、神经网络模型、智能机器人等前沿技术&#xff0c;正带来一场跨学科的革命。这种结合不仅推动了科技进步&#xff0c;也在医疗、教育、娱乐等…

docker 运行自定义化的服务-后端

docker 运行自定义化的服务-前端-CSDN博客 运行自定义化的后端服务 具体如下&#xff1a; ①打包后端项目&#xff0c;形成jar包 ②编写dockerfile文件&#xff0c;文件内容如下&#xff1a; # 使用官方 OpenJDK 镜像 FROM jdk8:1.8LABEL maintainer"ATB" version&…

NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)

记忆化搜索 在搜索的过程中&#xff0c;如果搜索树中有很多重复的结点&#xff0c;此时可以通过⼀个"备忘录"&#xff0c;记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时&#xff0c;直接在"备忘录"⾥⾯找结果。其中&#xff0c;搜索树中的⼀个⼀个结点…

【时时三省】(C语言基础)用switch语句实现多分支选择结构 例题

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 例题&#xff1a; 用switch语句处理菜单命令。在许多应用程序中&#xff0c;用菜单对流程进行控制&#xff0c;例如从键盘输入一个 A 或 a 字符&#xff0c;就会执行A操作&#xff0c;输入一…