简单多状态dp问题:从按摩师到股票买卖

告别Mac自带终端:iTerm2 + Oh My Zsh 保姆级配置指南(含国内镜像源) 本文提供了一份详细的Mac终端优化指南,涵盖iTerm2、Oh My Zsh和Homebrew的配置流程,特别针对国内用户提供镜像源解决方案。通过安装现代化工具链和优化配置,帮助开发者打造高效、美观的终端工作环境,提升日常开发效率。 阅读详情

目录

按摩师

打家劫舍2

删除并获得点数

粉刷房子

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

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

买卖股票的最佳时机Ⅲ

买卖股票的最佳时机Ⅳ

总结


按摩师

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

class Solution {
public:
    int massage(vector<int>& nums) {

        int m=nums.size();
        if(m==0)return 0;
        vector<int> f(m);//选
        vector<int> g(m);//不选
        f[0]=nums[0];
        for(int i=1;i<m;i++){
            f[i]=g[i-1]+nums[i];
            g[i]=max(f[i-1],g[i-1]);
        }
        return max(f[m-1],g[m-1]);
    }
};

打家劫舍2

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

本题和按摩师或者打家劫舍1非常相似,这里就是一个环形,我们仅仅只需要分析第0个位置偷还是不偷,如果第0个位置偷,那第1个和最后一个不能偷,如果第0个不偷,那剩下的随意

这样的好处是转换问题

class Solution {
public:
    int rob(vector<int>& nums) {
        int ret1,ret2;//记录结果
        int n = nums.size();
        if (n == 0)
            return 0;
        if(n==1)
            return nums[0];
        if(n==2){
            return max(nums[0],nums[1]);
        }
        vector<int> f(n); // 选
        vector<int> g(n); // 不选
        
        //不偷(1,n-1)
        f[1] = nums[1];
        for (int i = 2; i < n; i++) {
            f[i] = g[i - 1] + nums[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }
        ret1= max(f[n - 1], g[n - 1]);

        //偷(2,n-2)
        vector<int> x(n); // 选
        vector<int> y(n); // 不选
        x[2]=nums[2];
        for (int i = 2; i < n; i++) {
            x[i] = y[i - 1] + nums[i];
            y[i] = max(x[i - 1], y[i - 1]);
        }
        ret2= max(x[n - 2], y[n - 2])+nums[0];
        return max(ret1,ret2);
    }
};

删除并获得点数

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

本题的题意就是选择数字,选择了一个数字之后,不能选数字+1和数字-1的数字了(言外之意就是不能选择相邻的数字)

读完题之后有点类似打家劫舍,只不过打家劫舍是连续变大的数字,但这里可能重复且可能不连续且可能不是连续变大

所以需要转化,在增开一个数组,然后映射进去,arr[i]表示当前位置有多少个i

转换成打家劫舍问题即可

class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        int m=nums.size();
        int arr[10001]={0};
        for(auto e:nums){
            arr[e]+=e;
        }
        //打家劫舍
        vector<int> f(10001),g(10001);
        f[0]=arr[0];//必选
        g[0]=0;//不选
        for(int i=1;i<10001;i++){
            f[i]=g[i-1]+arr[i];
            g[i]=max(f[i-1],g[i-1]);
        }
        return max(f[10000],g[10000]);
    }
};

粉刷房子

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

本题的题意:给你一个数组,从上往下一行一行的选,每行之间选的数字不能相邻,使得选择的数的总和最小

本质就是带点限制的路径问题

动态表示:dp[i][j]:表示从上往下选到i行j列数字时,最小花费,此时要注意不能选[i-1][j]的

然后最后返回dp最后一行三个位置的最小值即可

class Solution {
public:
    int minCost(vector<vector<int>>& costs) {
        int n=costs.size();
        vector<int> x(n),y(n),z(n);
        x[0]=costs[0][0];
        y[0]=costs[0][1];
        z[0]=costs[0][2];
        for(int i=1;i<n;i++){
            x[i]=min(y[i-1],z[i-1])+costs[i][0];
            y[i]=min(x[i-1],z[i-1])+costs[i][1];
            z[i]=min(y[i-1],x[i-1])+costs[i][2];
        }
        return min(min(x[n-1],y[n-1]),z[n-1]);
    }
};

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

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

很明显需要多状态表示,一个状态是无法表示清楚,因为你当天结束之后处于什么状态是题意给出的

所以按照题意,需要三个状态,买入,可交易,冷冻期

最重要的是这三个状态之间如何转换,当出现多状态的时候我们很容易混乱,此时需要状态机

箭头的起点表示昨天处于什么状态,经过今天的操作之后,变为什么状态

所以我们要考虑每个状态可以由其他或者自己的状态转换吗

比如昨天处于买入状态,经过今天的卖出,得到利润之后,今天结束处于冷冻期状态

就这样推出所有的状态,然后写出状态转移方程即可

此时需要开3xn的空间,0表示买入状态,1表示可交易状态,2表示冷冻期

那dp[0][j]:表示当天结束之后,处于买入状态,此时的最大利润

那dp[1][j]:表示当天结束之后,处于可交易状态

那dp[2][j]:表示当天结束之后,处于冷冻期状态

那么状态转移方程很容易得出

dp[0][j]=max(dp[1][j-1]-prices[j],dp[0][j-1]);
dp[1][j]=max(dp[1][j-1],dp[2][j-1]);            
dp[2][j]=dp[0][j-1]+prices[j];   

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

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

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

这个对比上一题较为简单,只需要两个状态即可,因为没有冷冻期

所以直接推导状态转移方程即可

分买入和可交易状态

买入只要不卖出仍然处于买入状态+可交易状态经过买入之后到达买入状态

可交易状态只要不交易仍然处于可交易状态+买入经过卖出后到达可交易状态

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int m=prices.size();
        vector<vector<int>> dp(2,vector<int>(m));
        dp[0][0]=0-fee-prices[0];
        for(int j=1;j<m;j++){
            //分买入和可交易状态
            dp[0][j]=max(dp[0][j-1],dp[1][j-1]-fee-prices[j]);
            dp[1][j]=max(dp[0][j-1]+prices[j],dp[1][j-1]);
        }
        return max(dp[0][m-1],dp[1][m-1]);
    }
};

买卖股票的最佳时机Ⅲ

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

注意题意说最多交易两次,这是说明可以交易0次交易1次交易2次,并且不能连续买入,必须等到上一次买入卖出后才能再次买入

根据经验+题目要求,这种一维的题意,dp表不一定是一维,要根据题目来

假设dp[i]表示:第i天结束之后,所能获得的最大利润

很明显状态少了,因为第i天结束之后,你可能处于买入状态,也可能处于卖出状态

所以至少是f[i]和g[i],表示两个结束之后的状态

但是这里题意要求最多两次交易,所以还需要增加状态

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

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

当状态过多的时候,需要根据状态机不重不漏的推出状态转移方程

状态机中的边表示,起点表示昨天,边表示今天的操作,箭头表示结束后的状态

(昨天经过了今天的什么操作之后变为了什么状态)

比如f[i][j]:很明显只要i-1天处于买入,i天什么都不做也处于买入,此时交易次数不变

昨天是卖出,今天买入之后就会处于买入状态,此时交易次数也不变

只有当昨天处于买入,今天卖出之后交易次数才增加

初始化中两个细节,为了不能越界操作

1:可以看到f中可能会访问i-1,g当中会访问i-1和j-1,此时填表时先填第一行

j-1的意思是当状态g[i][0]的时候才会越界,并且此时的意思是昨天的交易次数是-1,经过今天的卖出之后交易次数+1变为0处于卖出状态,很明显交易次数不可能为-1

所以防止越界操作,我们可以增加if判断,当j-1>=0时才对比max

2:初始化第一行时,不要设为-INT_MIN,因为可能会导致溢出,g[i-2][j]-p[i]这里做减法可能会溢出,所以我们可以设一个很大的负数,大到题目怎么减也不会溢出

也就是-0x3f3f3f3f,这个是-INT_MIN的一半

返回值是g表,因为如果是f表,你手里有股票,怎么样都不是最大例利润

class Solution {
public:
    int MIN=-0x3f3f3f3f;
    int maxProfit(vector<int>& prices) {
        int m=prices.size();
        vector<vector<int>> f(m,vector<int>(3)); 
        vector<vector<int>> g(m,vector<int>(3));
        //初始化
        f[0][0]=-prices[0],f[0][1]=MIN,f[0][2]=MIN;
        g[0][0]=0,g[0][1]=MIN,g[0][2]=MIN;
        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]);
                if(j-1>=0){
                    g[i][j]=max(g[i-1][j],f[i-1][j-1]+prices[i]);
                }
                else{
                    g[i][j]=g[i-1][j];
                }
            }
        }
        return max(max(g[m-1][0],g[m-1][1]),g[m-1][2]);
    }
};

其中的if判断就是刚刚说的优化点,之前说的是新增一行或者一列,但是需要注意下标的映射关系,这里是直接if判断了

还有就是MIN的取值是-0x3f3f3f3f

初始化那里注意一下怎么取值不影响下面的填表

买卖股票的最佳时机Ⅳ

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

这道题和Ⅲ一样的,Ⅲ讲解的时候已经抽象为j次交易次数了,所以仅仅把常数2的地方更改为k次即可

k可以取小一点,因为天数限制了最大交易次数

class Solution {
public:
    const int MIN=-0x3f3f3f3f;
    int maxProfit(int k, vector<int>& prices) {
        int m = prices.size();
        k=min(k,m/2);
        vector<vector<int>> f(m, vector<int>(k+1,MIN));
        vector<vector<int>> g(m, vector<int>(k+1,MIN));
        // 初始化
        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]);
                if (j - 1 >= 0) {
                    g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i]);
                } else {
                    g[i][j] = g[i - 1][j];
                }
            }
        }
        int ret=0;
        for(int i=0;i<=k;i++){
            ret=max(ret,g[m-1][i]);
        }
        return ret;
    }
};

以下是记忆化搜索的方案

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    vector<vector<vector<int>>> memo; // 备忘录:memo[i][j][hold]
    
    int maxProfit(int k, vector<int>& prices) {
        int m = prices.size();
        // 边界:空数组/1天/0次交易,直接返回0
        if (m <= 1 || k == 0) return 0;
        
        // 优化:k≥m/2时等价于无次数限制,用贪心(递归也能处理,但贪心更快)
        if (k >= m / 2) {
            int res = 0;
            for (int i = 1; i < m; i++) {
                if (prices[i] > prices[i-1]) res += prices[i] - prices[i-1];
            }
            return res;
        }
        
        // 初始化备忘录:三维数组,初始值为-INF(标记未计算)
        // 维度:天数m × 剩余交易次数k+1 × 持有状态2(0/1)
        memo = vector<vector<vector<int>>>(m, vector<vector<int>>(k+1, vector<int>(2, -INF)));
        
        // 递归入口:第0天,剩余k次交易,不持有股票
        return dfs(0, k, 0, prices);
    }
    
    // 递归函数:从第i天开始,剩余j次交易,hold=0/1的最大收益
    int dfs(int i, int j, int hold, vector<int>& prices) {
        // 边界1:遍历完所有天数
        if (i == prices.size()) return 0;
        // 边界2:无剩余交易次数,且不持有 → 收益0;持有 → 只能烂手里,收益0(不如不买)
        if (j == 0) return hold ? 0 : 0;
        
        // 记忆化:已计算过的子问题,直接返回
        if (memo[i][j][hold] != -INF) return memo[i][j][hold];
        
        int res = 0;
        if (hold == 0) {
            // 不持有:可选「不操作」或「买入」
            res = max(
                dfs(i+1, j, 0, prices),          // 不操作
                dfs(i+1, j, 1, prices) - prices[i] // 买入(花钱)
            );
        } else {
            // 持有:可选「不操作」或「卖出」(卖出扣1次交易)
            res = max(
                dfs(i+1, j, 1, prices),          // 不操作
                dfs(i+1, j-1, 0, prices) + prices[i] // 卖出(赚钱,剩余交易-1)
            );
        }
        
        // 记录结果到备忘录
        memo[i][j][hold] = res;
        return res;
    }
};

hold=0和1是区分了f表和g表

总结

这里主要学习了简单多状态dp问题

这类问题是 DP 入门到进阶的核心,特征是「状态维度少(1-3 维)、状态类型有限(2-3 种)、转移逻辑清晰」

维度单状态 DP(如不同路径)简单多状态 DP(如股票 / 按摩师)
状态定义仅 1 种状态(如dp[i]= 到 i 的路径数)多种互斥状态(如持有/不持有「选 / 不选」)
状态转移仅依赖前序 1 种状态的转移不同状态间相互转移(如持有→不持有,不持有→持有)
核心难点找状态转移方程定义清晰的状态类型 + 梳理状态间的转移逻辑
  • 二元状态:选 / 不选(按摩师、打家劫舍)、持有 / 不持有(股票系列)、冷冻 / 非冷冻(股票含冷冻期);
  • 三元状态:持有 / 非冷冻不持有 / 冷冻不持有(股票冷冻期);
  • 分层状态:交易次数 + 持有 / 不持有(最多 k 次交易)。

这类问题的解法高度模板化,按以下 5 步走,能解决 90% 的简单多状态 DP 问题:

步骤 1:定义 “互斥且全覆盖” 的状态(核心中的核心)

  • 核心原则:

    1. 互斥:不同状态之间无重叠(比如 “持有股票” 和 “不持有股票” 不可能同时发生);

    2. 全覆盖:所有可能的情况都能被状态包含(比如股票问题中,任意一天只有 “持有 / 不持有” 两种情况);

    3. 少而精:状态数越少越好(优先 2-3 种,避免冗余)。

  • 举例:

    • 按摩师:f[i](选第 i 个)、g[i](不选第 i 个);

    • 股票冷冻期:dp[0][i](持有)、dp[1][i](非冷冻不持有)、dp[2][i](冷冻不持有);

    • 最多 k 次交易:dfs(i,j,hold)(第 i 天、剩余 j 次、是否持有)。

步骤 2:推导状态转移方程(枚举所有合法操作)

  • 核心逻辑:对每个状态,枚举 “当前能做的所有合法操作”,转移到下一个状态,并取最优值(最大 / 最小);

  • 推导模板:

    plaintext

    对于状态S(i):
    S(i) = max/min(
        操作1 → 转移到S(i)的前驱状态值 + 操作收益,
        操作2 → 转移到S(i)的另一前驱状态值 + 操作收益,
        ...
    )
    
  • 举例(股票含冷冻期):

    • 持有(dp [0][i]):要么前一天持有(不操作),要么前一天非冷冻不持有(买入)→ max(dp[0][i-1], dp[1][i-1]-prices[i]);

    • 冷冻不持有(dp [2][i]):只能前一天持有(卖出)→ dp[0][i-1]+prices[i]。

步骤 3:初始化边界状态(避免越界 / 逻辑错误)

  • 核心原则:

    1. 初始状态必须是 “绝对合法” 的(比如第 0 天持有股票,收益只能是-prices[0]);

    2. 非法状态用0x3f3f3f3f/-0x3f3f3f3f标记(比如第 0 天不可能冷冻,设为负无穷);

    3. 空数组 / 边界输入(如 k=0、m=0)需单独处理。

  • 避坑点:

    • 不要漏初始化 “0 次交易”“第 0 天” 等基础状态;

    • 不要用未初始化的状态参与转移

步骤 4:确定结果的取值范围(遍历所有合法最终状态)

  • 核心原则:最终结果是 “所有合法最终状态的最优值”,而非单一状态;

  • 避坑点:

    • 股票问题中,最后一天持有股票无意义,只需比较 “不持有” 的所有状态;

    • 最多 k 次交易中,需遍历 0~k 次交易的状态,而非仅取 k 次(比如 k=2 但 1 次交易收益更高)。

步骤 5:优化(可选,优先实现再优化)

  • 空间优化:若状态仅依赖前一步(如dp[i]仅依赖dp[i-1]),用变量替代数组(如按摩师问题从 O (n)→O (1));

  • 时间优化:特殊场景下的贪心替代(如 k≥m/2 时的股票问题);

  • 记忆化优化:递归解法中必须加备忘录,避免重复子问题。

三、高频避坑要点

  1. 状态定义模糊:比如把 “交易次数” 的扣减时机搞混(买入扣 / 卖出扣),导致转移逻辑全错;→ 解决:先写清 “交易次数按什么算”(比如 “一次完整交易 = 买入 + 卖出,卖出时扣”),再定义状态。

  2. 转移时访问未初始化状态:比如用dp[0][j](未初始化)参与max比较;→ 解决:先初始化基础状态(如 0 次交易),再按顺序转移。

  3. 结果取值错误:比如仅取 k 次交易的状态,忽略 0~k-1 次;→ 解决:遍历所有合法的最终状态,取最优值。

  4. 边界未处理:比如空数组、k=0、m=1 时直接访问数组;→ 解决:开头先判断边界条件,直接返回 0。

  5. 递归栈溢出:纯递归解 m=1e3 的问题;→ 解决:要么转递推 DP,要么对 k≥m/2 的场景做贪心优化。

四、简单多状态 DP 的核心思维:“状态机”

所有简单多状态 DP 问题,本质都可以抽象成有限状态机(FSM):

  • 每个状态是状态机的一个节点;

  • 状态转移是节点间的有向边(边的权重是操作的收益);

  • 解题就是 “遍历状态机,找到从初始节点到最终节点的最优路径”。

简单多状态 DP 问题的关键就是:同一时间点(比如 “第 i 天”)只会处于「唯一的一个状态」,所有状态彼此互斥,且你必须把这些互斥状态全部罗列出来(不重不漏) —— 这是这类问题能被 DP 解决的核心前提。

浅谈车载控制器产线EOL实现方式 1、控制器生产产线上电路检测设计 2、客户总装产线检测设计 阅读详情

相关推荐

西工大noj100题python2024第一季1-10

【代码】西工大noj100题python2024第一季1-10。

weixin_70523540的博客 1800

简单多状态dp问题:从打家劫舍到股票买卖

多状态 DP 适用于 每个决策点存在多种可能状态,且状态间存在依赖关系 的问题

feng_qi0325的博客 747

[漏洞剖析]JeecgBoot queryFieldBySql注入与JDBC连接滥用:从内存马植入到RCE的完整攻击链

本文深度剖析了JeecgBoot框架中queryFieldBySql接口的SQL注入漏洞及其引发的完整攻击链。攻击者利用该漏洞,通过Freemarker SSTI植入隐蔽的内存马,并进一步滥用JDBC连接测试功能,借助H2数据库特性实现远程命令执行(RCE),揭示了低代码平台中功能滥用与安全配置疏忽带来的严重风险。

weixin_29232121的博客 115

【 C/C++ 算法】入门动态规划 ----- 简单多状态 dp 问题》打家劫舍 和 股票买卖问题

本章是dp的第三章,从第一章的简单理解dp的核心框架和写法&一维dp,再到第二章的路径问题&二维dp,到本章的多状态dp问题,本章将结合前面的所有基础引入多状态这个问题,并将由浅到深的从简单的打家劫舍两状态的dp到最后股票问题的四状态dp进行以练代学的方式学习。

溟洵的博客 2726

电化学阻抗谱(EIS)在锂离子电池中的应用

摘要电化学阻抗谱(electrochemical impedance spectroscopy, EIS)是一种重要的电化学测试方法,在锂离子电池动力学反应机理研究及动力学参数测量等方面具有广泛的应用。在锂离子电池运行过程中,各反应步骤的动力学参数及时间常数不同,而EIS可以在较宽的频率范围内对体系施加小幅正弦激励信号,使得在特定频率下突出特定时间常数的电极过程,从而将复杂的电极过程分离,实现单一电极过程动力学的分析。通过对交流阻抗信息的研究,也可以为锂离子电池及其他电池的应用与管理、电化学过程设计及电极材

qiushireader的博客 2651

Python爬虫实战:手把手教你用Selenium绕过药监局网站的反爬机制(附完整代码)

本文详细介绍了如何使用Selenium绕过药监局网站的反爬机制,提供了一套完整的Python爬虫实战方案。通过浏览器指纹伪装、动态等待策略、会话维持技巧以及分布式采集设计,帮助开发者高效爬取药监局数据,解决政府类网站常见的反爬挑战。

weixin_42620255的博客 738

动态规划课堂3-----简单多状态问题(买卖股票最佳时机)

本片文章详细介绍了动态规划(dp)的多状态问题,本文所有dp问题分析和代码编写均按照模板进行,运用打家劫舍的经典问题来结合题目叙述,最后解决一道买卖股票的最佳时机问题。

2301_80035594的博客 2343

全面分析总结解决Could not transfer artifact org.apache.maven.plugins等此类问题的方法

全面分析总结解决Could not transfer artifact org.apache.maven.plugins,Could not transfer artifact xxx from/to xxx等此类问题的方法

ccjjjjdff的博客 1万+

【动态规划】简单多状态的dp问题&&股票问题

在上一篇有关动态规划的博客中,谈到做这类题目的步骤,有需要的可以点这个链接:【动态规划】斐波那契额数列模型。继续分享这个模型类型的题目。

zxctsclrjjjcph的博客 1476

ESP32学习笔记03-日志打印

日志分为5个等级。

Car12 1415

iOS应用突然无法从App Store获取到内购(IAP)产品列表的解决

问题现象 Apple开发中,在应用中嵌入内购(IAP)功能的小伙伴们可能会发现,吃着火锅唱着歌,突然App就无法获取到产品列表了,而且产品请求操作并不会返回任何错误。 此时检查发现,并没有对App的内购逻辑做任何改动。 那么,这是什么原因导致的呢? Let’s find out!???? 问题分析 1. 排除其它原因 首先,你先得排除不是你IAP内购逻辑变更或其他原因导致的。 在SKProductsRequestDelegat代理实现的productsRequest方法里下断点: func produc

享受开发,颠倒银河 6142

【动态规划】深入动态规划:简单多状态问题算法剖析

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

2403_87459748的博客 1638

lammps案例:扭转

扭转有两种方式,一是固定一端旋转另外一端,二是两端沿相反的方向旋转。案例为两侧旋转方式,扭转后的效果如图所示。

lammps_jiayou的博客 1199

【动态规划算法】(简单多状态dp问题入门与经典题型解析)

本文介绍了动态规划中的多状态DP问题,以按摩师预约问题为例,详细讲解了状态定义、转移方程和初始化方法。多状态DP通过增加维度来描述复杂场景中的额外信息,如是否选择当前元素。文章对比了单状态与多状态DP的区别,强调多状态DP能更完整地表达问题信息,从而做出正确决策。通过具体例题分析,帮助读者理解如何将复杂问题拆解为可递推的子结构,并建立清晰的多状态DP解题框架。

承于所学,探技术之渊;以代码求政,寻成长之道。 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【动态规划】C++简单多状态dp问题(打家劫舍、粉刷房子、买卖股票的最佳时机...)

本文通过一系列例题进行对 简单多状态的dp问题的理解

卜及中的博客 1333

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

多状态dp入门题目

完成一些简单的多状态dp: 1.按摩师 2.打家劫舍 II 3.删除并获得点数 4.粉刷房子 5.买卖股票的最佳时机含冷冻期 6.买卖股票的最佳时机含手续费 7.买卖股票的最佳时机 III 8.买卖股票的最佳时机 IV

分享 C/C++、Linux、网络的学习历程与实操心得~ 不追求一蹴而就,只坚持日积月累。未来还将拓展更多技术领域,愿与所有热爱技术的伙伴一起,在探索中成长,在坚持中进步! 607

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

动态规划核心模型精讲(上篇):斐波那契模型、路径问题与多状态DP

动态规划的魅力在于其对"无后效性"的精妙运用:当前决策只依赖已有的状态信息,未来的选择不会影响过去的最优解。这种特性使其成为处理多阶段决策问题的利器,但初学者常因复杂模型望而却步。本文将聚焦最基础的动态规划模型,通过斐波那契数列的递归优化、网格路径的状态转移等实例,带你掌握状态定义、转移方程构建等核心方法,为后续学习子序列、背包等复杂问题夯实基础。

2301_81073317的博客 979

【动态规划】简单多状态dp问题:按摩师,打家劫舍,删除并获得点数,粉刷房子,买卖股票的最佳时机

本文总结了5道动态规划问题的解题思路和代码实现:1. 按摩师问题使用两个状态数组表示接受/不接受预约的最长时间;2. 打家劫舍II通过分类讨论将环形问题转为线性问题;3. 删除点数问题转换为类似打家劫舍的解法;4. 粉刷房子使用三个数组分别记录不同颜色的最小成本;5. 含冷冻期的股票买卖问题通过三个状态表示不同交易状态。这些题目都展示了动态规划在解决最优化问题中的灵活应用。

记录了从0学习Java技术栈的日常 237

动规:简单多状态模型

本文总结了多道动态规划问题的解题思路与代码实现,包括按摩师、打家劫舍II、删除并获得点数、粉刷房子以及买卖股票系列问题。文章通过状态转移方程和状态机分析,详细讲解了各类问题的解法,并提供了空间优化技巧。对于股票买卖问题,特别分析了含冷冻期、手续费和次数限制的情况,展示了如何通过创建多个状态表来处理复杂条件。所有解法均采用清晰的代码结构,便于理解和应用。

_dindong的博客 843

简单多状态dp问题

本文总结了七道动态规划经典题目:按摩师、打家劫舍(环形)、删除并获得点数、粉刷房子、买卖股票(含冷冻期、手续费、最多两次交易)。核心思想均为状态机建模,通过定义状态转移方程实现最优解。关键技巧包括:状态表示、边界初始化、填表顺序与返回值处理。代码均基于动态规划,时间复杂度多为O(n),空间可优化至O(1)。适用于解决“不相邻”、“最大收益”类问题。

budingxiaomoli的博客 147

动态规划——简单多状态dp

多状态dp就是dp[i]可能不只有一种状态 我们要分析这些状态之间的含义关系当多种状态可以互相转换的时候最好画一张图 分析关系 (买股票问题很典型的状态之间互相转换)分析清楚之后可以得出状态转移方程。

zc331的博客 281

动态规划进阶:从打家劫舍到股票买卖的多状态DP建模与实战

动态规划(DP)是解决最优化问题的核心算法思想,其关键在于定义状态与状态转移方程。当问题决策受多种因素影响时,单一状态往往无法描述完整信息,此时需要引入多状态DP,即状态机模型。该模型通过定义系统在每一步可能处于的多个离散状态(如持有/不持有股票、偷/不偷房屋),并明确状态间基于操作的转移规则,能精准刻画复杂决策过程。这种建模方法在算法竞赛和工程实践中价值巨大,尤其适用于处理序列决策问题,如资源调度、路径规划、金融交易策略等。本文以经典的“打家劫舍”和“股票买卖”问题为切入点,深入剖析多状态DP的建模思路、

weixin_33946605的博客 419

动态规划 - 简单多状态 dp 问题

摘要:本文系统介绍了简单多状态动态规划(DP)问题及其解法。这类问题的特点是每个阶段存在有限个状态(通常2-4个),状态间转换规则明确。文章通过打家劫舍、股票买卖、粉刷房子等经典例题,详细阐述了多状态DP的三要素:最优子结构、重叠子问题和有限状态集合。针对不同问题,给出了状态定义、转移方程、初始化和填表顺序的具体方法。特别强调了如何将环形问题转化为线性问题处理,以及交易次数限制下的状态设计技巧。最后提供了力扣相关题目的代码实现,展示了多状态DP的通用解题框架。

Small_entreprene的博客 1149

简单多状态问题

/0买股票,1有股票不卖,2,没有股票也不买,3,表示卖股票。//0是买入的状态,1是可交易,2是冷却期。//f表示买入的g表示卖出。

2501_93654724的博客 399

二、动规_简单多状态dp问题_买卖股票系列问题

定义两个二维数组buy和sellbuy[i][j]:表示在第i天结束时,恰好进行了j笔交易且当前持有股票的最大利润。sell[i][j]:表示在第i天结束时,恰好进行了j笔交易且当前不持有股票的最大利润。

YQ20210216的博客 900

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

注意建dp表,不限制交易次数,只要在限制范围内即可,每一个位置记录三种交易的可能,即每个交易次数的收益情况。初始化时由于[i][j]位置要用到[i-1][j-1]位置的值正常情况下要初始化一行一列,对关于j次数变化的状态转移方程做转化,变为两条语句,判断了j交易次数的合法情况,避免了j在0位置依赖-1位置初始化的情况。学会运用状态机来表示每个状态之间的关系,罗列不同的状态,划线,线的起点代表上一个位置的状态,箭头指向当前状态,过程中代表做了些什么,总体要表示由什么状态可以到达当前状态。

关注学习C++领域,感谢陪伴,共同进步! 362
上一篇: Redis缓存深度解析:20%数据应对80%请求
下一篇: 动态规划核心:数组问题实战
Fcw0551
博客等级 码龄2年 330粉丝 115原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值