动态规划——多状态动态规划问题

news2024/11/26 8:18:32

目录

一、打家劫舍 

二、打家劫舍 II 

三、删除并获得点数

四、粉刷房子 

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

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

七、买卖股票的最佳时机III

八、买卖股票的最佳时机IV


一、打家劫舍 

打家劫舍

第一步:确定状态表示

当我们每次偷到第i间房子时,我们存在两种状态,即可以选择偷或者不偷该房子的金额。所以我们需要有两张dp表。

f[ i ] 表示偷到第 i 间房子时,小偷选择偷第  i 间房子的金额时,偷窃到的总金额最大。g[ i ]表示偷到第 i 间房子时,小偷选择不偷第  i 间房子的金额时,偷窃到的总金额最大。

第二步:推出状态转移方程

第三步:初始化dp表

我们在使用状态转移方程时,会用到 i-1位置的值,那么如果 i 为0的话,就会有越界访问的问题,所以我们需要初始化,f[0] = nums[0],g[i] = 0。

填表顺序:因为在填写 i 位置的值时,我们要用到 i-1位置的值,所以需要从左往右依次填写。

最后的返回值:我们要返回光顾完所有房子后,所能偷到的最大金额,所以需要返回f[n-1] 和 g[i-1]两者的最大值。

解题代码:

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

 


二、打家劫舍 II 

打家劫舍II

打家劫舍II和打家劫舍问题唯一不同的是,这道题的房子是围成一个圈的。我们可以将它转换成打家劫舍问题去处理。

其他方法就和打家劫舍问题一样了。 

返回值就是上面两种情况的最大值。

解题代码:

class Solution 
{
public:
    int rob(vector<int>& nums) 
    {
        int n = nums.size();
        return max(nums[0] + rob1(nums, 2, n-2), rob1(nums, 1, n-1));
    }

    int rob1(vector<int>& nums, int left, int right)
    {
        int n = nums.size();
        if(left > right)
            return 0;

        vector<int> f(n);
        vector<int> g(n);
        f[left] = nums[left]; // 区间的起始位置是left
        for(int i = left; i <= right; i++)
        {
            f[i] = g[i-1] + nums[i];
            g[i] = max(g[i-1], f[i-1]);
        }
        return max(g[right], f[right]); // 区间的最右是right
    }
};


三、删除并获得点数

删除并获得点数

预处理:我们需要注意题目说明中的这一句:选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除所有等于 nums[i] - 1 和 nums[i] + 1 的元素。 

也就是说,你在拿到nums[i]的点数后,就不能选择它前一个和后一个元素了。比如,nums[i]为5,拿到5这个点数后,你就不能再拿3和4了。这个要求是不是又和打家劫舍很像了。所以我们最终还是将这个问题转换成了打家劫舍问题。

比如对于示例2:

解题代码:

class Solution 
{
public:
    int deleteAndEarn(vector<int>& nums) 
    {
        int arr[10001] = {0};
        for(auto x : nums)
            arr[x] += x;

        vector<int> f(10001);
        vector<int> g(10001);
        f[0] = arr[0];
        for(int i = 1; i < 10001; i++)
        {
            f[i] = g[i-1] + arr[i];
            g[i] = max(g[i-1], f[i-1]);
        }
        return max(g[10000], f[10000]);
    }
};


四、粉刷房子 

粉刷房子

第一步:确定状态表示

红:0,蓝:1,绿:2。

dp[i][j]:表示刷到第i个房子时,将其涂成第j种颜色时的最小花费。

第二步:推出状态转移方程

第三步:初始化dp表

在使用dp表时,要使用i-1,所以 i == 0时,就会发生越界访问的问题。所以初始化,

dp[0][0] =  costs[0][0],dp[0][1] = costs[0][1],dp[0][2] = costs[0][2]。

填表顺序:从上向下,从左到右

最后的返回值是最后一行的最大值。

解题代码:

class Solution 
{
public:
    int minCost(vector<vector<int>>& costs) 
    {
        int m = costs.size(), n = costs[0].size();
        // 红:0,蓝:1,绿:2
        // dp[i][j]:表示刷到第i个房子时,将其涂成第j种颜色时的最小花费
        vector<vector<int>> dp(m, vector<int>(3));
        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(dp[m-1][0], min(dp[m-1][1], dp[m-1][2]));
    }
};


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

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

第一步:确定状态表示

根据题意和示例,大的状态表示就是在第i天结束后,所获得的最大利润,而对于第i天来说,我们又有三种可能的状态:卖出,买入,冷冻期。

卖出状态:0,买入状态:1,冷冻期:2

所以说,dp[i][j]:表示第 i 天结束后,处于第 j 种状态时,所获的最大利润。

dp[i][0] 表示: 第 i 天结束之后,处于卖出状态,此时的最大利润。

dp[i][1] 表示: 第 i 天结束之后,处于买入状态,此时的最大利润。

dp[i][2] 表示: 第 i 天结束之后,处于冷冻期状态,此时的最大利润。

第二步:推出状态转移方程

对于上面的核心图,我们对卖出状态进行举例解释一下:

如果在第 i 天结束后处于卖出状态,需要看 i - 1 天是什么状态然后怎么做能够满足第 i 天结束处于卖出状态。

如果第 i - 1 天结束处于卖出状态,那第 i 天什么也不干,依旧处于卖出状态。

如果第 i - 1 天结束处于冷冻期,也就是说第 i 天不能进行任何操作,无法购买股票,当第 i 天结束后,就会结束冷冻期,进入卖出状态。

第三步:初始化dp表,dp[0][1] = -prices[0]。

从左往右,从上向下依次填表,最后返回最后一天的三种状态中的最大值。

解题代码:

class Solution 
{
public:
    int maxProfit(vector<int>& prices) 
    {
        int m = prices.size();
        vector<vector<int>> dp(m, vector<int>(3));
        dp[0][1] = -prices[0];
        // 卖:0,买:1,冷冻:2
        for(int i = 1; i < m; i++)
        {
            dp[i][0] = max(dp[i-1][0], dp[i-1][2]);
            dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i]);
            dp[i][2] = dp[i-1][1]+prices[i];
        }
        return max(max(dp[m-1][0], dp[m-1][1]), dp[m-1][2]);
    }
};

 


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

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

第一步:确定状态表示

根据题意,每一天都可能存在两种状态,买入状态和卖出状态。

所以,f[i]:表示第 i 天结束后,处于买入状态时,所获的最大利润。g[i]:表示第 i 天结束后,处于卖出状态时,所获的最大利润。

需要注意的是,每次卖出股票,需要支付手续费。

第二步:推出状态转移方程

第三步:初始化dp表,f[0] = -prices[0]。

填表顺序为从左往右依次填写,g[i]和f[i]一起填写。最后的返回值是f[m-1]和f[m-1]中的最大值。

解题代码:

class Solution 
{
public:
    int maxProfit(vector<int>& prices, int fee) 
    {
        int m =prices.size();
        vector<int> f(m);
        vector<int> g(m);
        f[0] = -prices[0];
        for(int i = 1; i < m; 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 max(f[m-1], g[m-1]);
    }
};

 


七、买卖股票的最佳时机III

买卖股票的最佳时机III

第一步:确定状态表示

首先,仍然是 dp[i] 表示第 i 天结束后所获得的最大利润。每一天有两种状态,卖出和买入状态。

而这道题和之前的题目不同的就是,它有交易次数的限制,只能够完成两笔交易。所以对于每一天来说,在卖出和买入状态之下,还有一种状态,那就是一直到第 i 天的交易次数。

所以,dp[i][j] :表示第 i 天结束后,完成了 j 次交易后,所获得的最大利润。0表示完成了0次交易,1表示完成了1次交易,2表示完成了2次交易。

f[i][j] :表示第 i 天结束后,处于买入状态时,完成了 j 次交易后,所获得的最大利润。

g[i][j] :表示第 i 天结束后,处于卖出状态时,完成了 j 次交易后,所获得的最大利润。

第二步:推出状态转移方程

第三步:初始化dp表

填表顺序为从左往右,从上往下依次填写,g[i]和f[i]一起填写。 

解题代码:

class Solution 
{
    const int n = -0x3f3f3f3f;
public:
    int maxProfit(vector<int>& prices) 
    {
        int m = prices.size();
        vector<vector<int>> f(m, vector<int>(3, n)); // 买入
        vector<vector<int>> g(m, vector<int>(3, n)); // 卖出
        f[0][0] = -prices[0], g[0][0] = 0;
        for(int i = 1; i < m; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i]);
                g[i][j] = g[i-1][j];
                if(j-1 >= 0)
                    g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i]);
            }
        }

        int ret = 0;
        for(int i = 0; i < 3; i++)
        {
            if(g[m-1][i] > ret)
                ret = g[m-1][i];
        }
        return ret;
    }
};

 


八、买卖股票的最佳时机IV

买卖股票的最佳时机IV

这一道题的思路,和买卖股票的最佳时机III一模一样,只是把最多交易次数限定成了一个未知数。我们所有的解题方法都与他相同。

解题代码:

class Solution 
{
    const int n = -0x3f3f3f3f;
public:
    int maxProfit(int k, vector<int>& prices) 
    {
        int m = prices.size();
        vector<vector<int>> f(m, vector<int>(k+1, n)); // 买入
        vector<vector<int>> g(m, vector<int>(k+1, n)); // 卖出
        f[0][0] = -prices[0], g[0][0] = 0;
        for(int i = 1; i < m; i++)
        {
            for(int j = 0; j <= k; j++)
            {
                f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i]);
                g[i][j] = g[i-1][j];
                if(j-1 >= 0)
                    g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i]);
            }
        }
        int ret = 0;
        for(int i = 0; i <= k; i++)
        {
            if(g[m-1][i] > ret)
                ret = g[m-1][i];
        }
        return ret;
    }
};

 

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

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

相关文章

navicat下载教程(包会的)

官网地址&#xff1a;Navicat | 下载 Navicat Premium 14 天免费 Windows、macOS 和 Linux 的试用版 第三方官网&#xff1a;https://pan.baidu.com/s/1kTgxwX84TPEqVfals38Mvw 一、下载navicat安装包 步骤1---试用版本 步骤2---下载windws系统的navicat 步骤3---查看安装…

ES6总结

1.let和const以及与var区别 1.1 作用域 var&#xff1a; 变量提升&#xff08;Hoisting&#xff09;&#xff1a;var 声明的变量会被提升到其作用域的顶部&#xff0c;但赋值不会提升。这意味着你可以在声明之前引用该变量&#xff08;但会得到 undefined&#xff09;。 con…

闯关leetcode——88. Merge Sorted Array

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/merge-sorted-array/description/ 内容 You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements …

计量校准公司对校准工程师,会有什么资质要求?

计量校准是指利用一些计量校准工具&#xff0c;对机器、仪器等进行测量和校准。来实现基本功能的正常使用。计量校准安排&#xff0c;是指根据委托方的要求&#xff0c;按照计量器具校准标准&#xff0c;向社会提供计量器具校准服务的安排。今天&#xff0c;我们就来看看计量校…

Django的请求与响应

Django的请求与响应 1、常见的请求2、常见的响应3、案例 1、常见的请求 函数的参数request是一个对象&#xff0c;封装了用户发送过来的所有请求相关数据。 get请求一般用来请求获取数据&#xff0c;get请求也可以传参到后台&#xff0c;但是传递的参数显示在地址栏。 post请求…

INDEMIND:扫地机器人,保“鲜”不保“熟”

从家庭“必备”到边角“鸡肋”。 新鲜却不保“熟” 作为新时代的网红产品&#xff0c;扫地机器人成为了很多装修攻略中的必备单品&#xff0c;但当年轻人真正使用后&#xff0c;心中却不免疑问&#xff0c;这真的是自己听到的那个“六边形战士”&#xff1f; 与所畅想的“甩手…

基于yolov8、yolov5的PCB板缺陷检测系统(含UI界面、数据集、训练好的模型、Python代码)

blog.csdnimg.cn/direct/6f53422ed9fd44dc8daad6dc5481c4c9.png) 项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8、yolov8 SE注意力机制 或 yolov5、yolov5 SE注意力机制 &#xff0c; 直接提供最少两个训练好的模型…

无人机之视觉技术篇

一、视觉传感器的类型 摄像头&#xff1a; 最常见的视觉传感器&#xff0c;能够捕捉可见光图像和视频。 通过单目、双目或多目摄像头的组合&#xff0c;无人机能够实现立体视觉&#xff0c;从而估算距离、深度&#xff0c;并进行物体识别和追踪。 红外传感器&#xff1a; …

猿人学— 第一届第1题(解题思路附源码)

猿人学 — 第1届第1题&#xff08;解题思路附源码&#xff09; F12进入开发者工具—> 发现停止在debugger处 —> 右键点击Never pause here后下一步 翻页&#xff0c;抓包后发现请求携带page和m两个参数&#xff0c;page应该就是页数&#xff0c;m则需要逆向 依次查找…

24.6 监控系统在采集侧对接运维平台

本节重点介绍 : 监控系统在采集侧对接运维平台 服务树充当监控系统的上游数据提供者在运维平台上 可以配置采集任务 exporter改造成探针型将给exporter传参和修改prometheus scrape配置等操作页面化 监控系统在采集侧对接运维平台 服务树充当监控系统的上游数据提供者在运…

web 0基础第二节 列表标签

1.有序列表 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>有序列表 比较重要</title>…

低代码BPM流程引擎:赋能业务流程的高效工具

什么是低代码BPM流程引擎&#xff1f; 低代码BPM流程引擎是一种通过图形化界面和简单配置&#xff0c;允许用户快速设计、管理和优化业务流程的软件工具。与传统的BPM解决方案相比&#xff0c;低代码平台降低了对专业开发人员的依赖&#xff0c;让业务人员也能参与到流程设计中…

Vivado - 在硬件中调试 Serial I/O (IBERT)

目录 1. 简介 2. 硬件平台 2.1 ZCU102 2.1.1 Clock Sources & Destinations 2.2 ZCU106 2.2.1 Clock Sources & Destinations 2.2.2 IP 配置 2.2.3 约束 3. 结果 3.1 创建 Links 3.1.1 IBERT UI 3.1.2 创建 Links 3.1.3 配置链路 3.1.4 扫描参数 3.1.5 …

国产AI工具「神笔马良」!只需上传剧本,AI一键成片!(附保姆级教程)

大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~&#xff08;AI资料点文末卡片自取&#xff09; 记得 AI 视频刚…

使用阿里巴巴的图

参考链接1 引用彩色图标可参考以下链接 &#xff08;到第三步 测试图标效果 的时候 还是可以保持之前的写法&#xff1a;<i/sapn class“iconfont icon-xxx”>也会出现彩色的&#xff09; 参考链接2 阿里巴巴字体使用 也可以直接将官网的代码复制过来到页面的css区域

想要去日本做IT,本篇文章给您一些中肯的建议!

关于在日本从事IT行业&#xff0c;以下是一些建议&#xff1a; 一、了解行业现状与趋势 行业需求旺盛&#xff1a;随着人工智能、大数据、云计算等技术的不断发展&#xff0c;日本IT行业对程序员的需求持续增长&#xff0c;特别是在金融科技、电子商务、游戏开发、移动应用等…

如何评估TPM管理咨询公司的人才培养效果?

在探讨如何评估TPM管理咨询公司的人才培养效果时&#xff0c;我们需要从多个维度进行深入分析&#xff0c;以确保评估的全面性和准确性。TPM管理咨询公司作为推动企业生产效率与质量管理提升的重要力量&#xff0c;其人才培养效果直接关系到咨询项目的实施效果及企业的长远发展…

3DCAT实时云渲染赋能2024广东旅博会智慧文旅元宇宙体验馆上线!

广东国际旅游产业博览会&#xff08;以下简称“旅博会”&#xff09;是广东省倾力打造的省级展会品牌&#xff0c;自2009年独立成展至今已成功举办十五届。2024广东旅博会于9月13—15日在广州中国进出口商品交易会展馆A区举办&#xff0c;线上旅博会“智慧文旅元宇宙体验馆”于…

Word 首行缩进 2 字符怎么设置?具体步骤演示

在日常的文档编辑和排版中&#xff0c;首行缩进是一个非常常见且重要的排版需求。尤其是在中文文档中&#xff0c;首行缩进能够提高文章的美观度和可读性&#xff0c;使文章结构更加清晰。那 Word 首行缩进 2 字符怎么设置呢&#xff1f;下面就给大家展示具体的操作步骤。 设置…

SA2601A ,600V高速风筒半桥栅极驱动芯片

描述 SA2601A是一款针对于双NMOS的半桥栅极驱动芯片&#xff0c;专为高压、高速驱动N型功率MOSFET和IGBT设计&#xff0c;可在高达600V电压下工作。 SA2601A内置VCC和VBS欠压(UVLO)保护功能&#xff0c;防止功率管在过低的电压下工作&#xff0c;提高效率。 SA2601A输入脚兼容3…