首页 > 其他分享 >动态规划之简单多状态 dp 问题(下)

动态规划之简单多状态 dp 问题(下)

时间:2024-10-24 20:46:43浏览次数:3  
标签:状态 int max vector prices 动态 规划 dp

文章目录

买卖股票的最佳时机

题目:买卖股票的最佳时机

在这里插入图片描述
思路

  • 状态表示:dp[i]表示第i天结束后,处于某个状态的最大利润,我们可以细分为,处于“买入”、“可交易”、“”三种状态

    • dp[i][0]表示:第 i 天结束后,处于“买入”状态的最大利润
    • dp[i][1]表示:第 i 天结束后,处于“可交易”状态的最大利润
    • dp[i][2]表示:第 i 天结束后,处于“冷冻期”状态的最大利润
  • 状态转移方程:

    • dp[i][0]:有两种状态可以到达
      • i - 1天也处于“买入”状态,今天什么也不做,仍处于“买入”状态,此时最大受益和i - 1天相同,即dp[i - 1][0]
      • i - 1天也处于“可交易”状态,今天买了股票,此时最大受益为dp[i - 1][1] - price[i]
      • 综上,dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
    • dp[i][1]:有两种状态可以到达
      • i - 1天也处于“可交易”状态,今天什么也不做,仍处于“可交易”状态,此时最大受益和i - 1天相同,即dp[i - 1][1]
      • i - 1天也处于“冷冻期”状态,今天什么也不做,仍处于“冷冻期”状态,此时最大受益和i - 1天相同,即dp[i - 1][2]
      • 综上,dp[i][1] = max(dp[i-1][1], dp[i-1][2])
    • dp[i][2]:只有一种状态可以到达
      • i - 1天也处于“买入”状态,今天卖股票,此时最大受益为dp[i][2] = dp[i - 1][0] + prices[i]
  • 初始化:

    • 0天处于买入状态,dp[0][0] = -prices[0]
    • `第0天处于可交易状态,无操作,dp[0][1] =0
    • 0天处于冷冻期状态,无操作,dp[0][2] = 0
  • 填表顺序:三个表从左向右一起填写

  • 返回值:卖出状态下的最大值 max(dp[n-1][1], dp[n-1][2])

C++代码

class Solution
{
public:
    int maxProfit(vector<int>& prices) 
    {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3));

        dp[0][0] = -prices[0];
        for (int i = 1; i < n; ++i) 
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);
            dp[i][2] = dp[i - 1][0] + prices[i];
        }

        return max(dp[n - 1][1], dp[n - 1][2]);
    }
};

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

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

在这里插入图片描述
思路

  • 状态表示:第i天结束后,所能获得的最大利润,这一天有两种状态,“买入”、“卖出”

    • f[i]表示第 i天结束后,处于“买入”状态的最大利润
    • g[i]表示第 i天结束后,处于“卖出”状态的最大利润。
  • 状态转移方程:

    • f[i]有两种状态到达
      • 前一天i - 1有股票,第i天啥也不做,收益最大为f[i - 1]
      • 前一天i - 1没有股票,第i天买入股票,收益最大为g[i-1] - prices[i]
      • 综上,f[i] = max(f[i-1], g[i-1] - prices[i])
    • g[i]有两种状态到达
      • 前一天i - 1没有股票,第i天啥也不做,收益最大为g[i -1]
      • 前一天i - 1有股票,第i天卖出股票,收益最大为f[i - 1] + prices[i] - fee
      • 综上,g[i] = max(g[i-1], f[i-1] + prices[i] - fee)
  • 初始化:

    • f[0]处于买入状态,此时f[0] = -price[0]
    • g[0] 处于没有股票状态,此时g[0] = 0
  • 填表顺序:两个表从左向右一起填写

  • 返回值:返回“卖出”状态下最后一天的最大值收益g[n - 1]

C++代码

class Solution
{
public:
    int maxProfit(vector<int>& prices, int fee) 
    {
        int n = prices.size();
        vector<int> f(n);
        vector<int> g(n);
        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]; 
    }
};

买卖股票的最佳时机 III

题目:买卖股票的最佳时机 III

在这里插入图片描述
思路

  • 状态表示:以某个位置为结尾,使用两个数组表示买入可交易两个状态,并加上一维表示交易次数

    • f[i][j]表示第 i 天结束后,完成了 j次交易,处于买入状态的最大利润
    • g[i][j]表示第 i 天结束后,完成了 j次交易,处于卖出状态的最大利润
  • 状态转移方程:

    • f[i][j]有两种状态到达

      • i - 1天处于买入,第i天什么也不做,此时最大利润f[i - 1][j]
      • i - 1天处于卖出,第i天买股票,此时最大利润g[i - 1][j] - price[i]
      • 综上,f[i][j] = max(f[i - 1][j], g[i - 1][j] - price[i])
    • g[i][j]有两种状态到达

      • i - 1天处于买入,第i天卖出股票,,此时最大利润f[i - 1][j - 1] + price[i]
      • i - 1天处于卖出,第i天什么也不做,此时最大利润g[i - 1][j]
      • 综上,f[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + price[i])
  • 初始化第一行,考虑第0 天只能处于买入过一次状态的情况, f[0][0] = -prices[0],其余状态为-INF(防止减法发生越界)

  • 填表顺序:从上往下,从左往右

  • 返回值:卖出状态的最大值,即g 表的最后一行的最大值max(g[n - 1][0], max(g[n - 1][1], g[n - 1][2]))

C++代码

class Solution 
{
    const int INF = 0x3f3f3f3f;
public:
    int maxProfit(vector<int>& prices) 
    {
        int n = prices.size();
        vector<vector<int>> f(n, vector<int>(3, -INF));
        vector<vector<int>> g(n, vector<int>(3, -INF));

        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]);
                g[i][j] = g[i - 1][j];
                if (j > 0)
                    g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]);
            }

        return max(g[n - 1][0], max(g[n - 1][1], g[n - 1][2]));
    }
};

买卖股票的最佳时机 IV

题目:买卖股票的最佳时机 IV

在这里插入图片描述
思路

  • 状态表示:以某个位置为结尾,使用两个数组表示买入可交易两个状态,并加上一维表示交易次数

    • f[i][j]表示第 i 天结束后,完成了 j次交易,处于买入状态的最大利润
    • g[i][j]表示第 i 天结束后,完成了 j次交易,处于卖出状态的最大利润
  • 状态转移方程:

    • f[i][j]有两种状态到达

      • i - 1天处于买入,第i天什么也不做,此时最大利润f[i - 1][j]
      • i - 1天处于卖出,第i天买股票,此时最大利润g[i - 1][j] - price[i]
      • 综上,f[i][j] = max(f[i - 1][j], g[i - 1][j] - price[i])
    • g[i][j]有两种状态到达

      • i - 1天处于买入,第i天卖出股票,,此时最大利润f[i - 1][j - 1] + price[i]
      • i - 1天处于卖出,第i天什么也不做,此时最大利润g[i - 1][j]
      • 综上,f[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + price[i])
  • 初始化第一行,考虑第0 天只能处于买入过一次状态的情况, f[0][0] = -prices[0],g[0][0] = 0其余状态为-INF(防止减法发生越界)

  • 填表顺序:从上往下,从左往右

  • 返回值:卖出状态的最大值,即g 表的g[n - 1][i]

k值可能太长,我们对k进行优化
k = min(k, n / 2);
C++代码

class Solution 
{
    const int INF = 0x3f3f3f3f;
public:
    int maxProfit(int k, vector<int>& prices)
    {
        int n = prices.size();
        k = min(k, n / 2);
        vector<vector<int>> f(n, vector<int>(k + 1, -INF));
        vector<vector<int>> g(n, vector<int>(k + 1, -INF));

        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]);
                g[i][j] = g[i - 1][j];
                if (j > 0)
                    g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]);
            }

        int ret = 0;
        for (int i = 0; i <= k; ++i)
            ret = max(ret, g[n - 1][i]);

        return ret;
    }
};

标签:状态,int,max,vector,prices,动态,规划,dp
From: https://blog.csdn.net/m0_74317866/article/details/143202780

相关文章

  • 【动态绘图】python 动态柱形图 动态折线图 bar_chart_race sjvisualizer
    本文主要介绍如何使用Python的bar_chart_race和sjvisualizer模块绘制动态柱形图和动态折线图。关于sjvisualizer包使用详细可见【动态绘图】上。一、实验环境1.1操作系统及Python环境本实验的所使用的操作系统为Windows1064位,Python版本为Python3.12.4,Python编译器......
  • Vue.js 投票排行榜:从零到完整实现详细教程” “新手友好:使用 Vue.js 构建一个实时投票
    效果图博客教程:使用Vue.js实现投票排行榜页面(详细步骤)在本篇博客教程中,我们将逐步带你实现一个投票排行榜页面,使用的是Vue.js框架。此项目适合前端开发新手,可以帮助你更好地理解Vue的基本功能和组件开发。目录项目介绍搭建项目基础结构实现榜单前3名展示实现倒计时功......
  • 综合能源系统分析的统一能路理论(三):《稳态与动态潮流计算》(Python代码实现)
     ......
  • 动态规划
    动态规划概述动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。由于动态规划并不是某种具体的算法,而是一种解决特定问题的方法,因此它会出现在各式各样的数据结构中,与之相关的题目种类也更为繁杂。一般的解题步骤解决动态规划问题,通常由两个步骤:......
  • 线性规划求解软件开发的PSP数据统计
    PSP报告1.计划(Planning)估算:本项目的主要目标是实现线性规划问题的优化模型,并通过GUI界面简化用户操作。根据任务复杂度,估算开发工作量约为40小时。2.开发(Development)2.1需求分析(Analysis)在项目中,需求包括以下几点:通过C++实现线性规划问题的优化模型。......
  • 树形限制的排列生成dp
    对于这类树形限制的生成排列的题记录两种不同的做法\(\color{blue}\textbf{[例题]}\)第一种方法(暴暴暴暴暴力dp)P4099[HEOI2013]SAOP3757[CQOI2017]老C的键盘第二种方法(容斥+dp)P5405[CTS2019]氪金手游题面生成一个大小为n的排列,满足n-1条形如p[x]>p[y]......
  • 树覆盖型dp
    遇到做过的题不会做,以后要好好改题......
  • 局部路径规划(Local planning)算法之——TEB轨迹规划
    1TEB算法原理TEB全程为TimeElasticBand(时间弹力带),通过对给定的全局轨迹进行修正,从而优化机器人的局部运动轨迹。他是常用的局部路径规划方法之一。TEB是基于图优化的方法,以g2o优化框架实现,它以机器人在各个离散时间的位姿和离散时刻之间的时间间隔为顶点,通过多目标优化,包括......
  • 线性 DP
    最长上升子序列问题是一个经典的线性动态规划问题。例题:B3637最长上升子序列分析:设原始数组为\(a\),定义状态\(dp_i\)表示以\(a_i\)结尾的上升子序列的最大长度。注意这个状态定义中有两个重点,第一个重点是\(dp_i\)只维护所有原始序列中以\(a_i\)结尾的上升子序列的信......
  • 经典的二次规划问题的标准形式
    公式9-33描述的是经典的二次规划问题的标准形式,它是支持向量机(SVM)等机器学习算法以及许多凸优化问题中的核心问题。该公式描述了一个最小化目标函数的问题,并且附带有不等式约束和等式约束。具体形式如下:......