zoukankan      html  css  js  c++  java
  • AcWing 1057. 股票买卖 IV Leetcode188. 买卖股票的最佳时机 IV 动态规划

    地址 https://www.acwing.com/problem/content/description/1059/

    给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。
    
    设计一个算法来计算你所能获取的最大利润,你最多可以完成 k 笔交易。
    
    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。
    
    输入格式
    第一行包含整数 N 和 k,表示数组的长度以及你可以完成的最大交易数量。
    
    第二行包含 N 个不超过 10000 的正整数,表示完整的数组。
    
    输出格式
    输出一个整数,表示最大利润。
    
    数据范围
    1≤N≤105,
    1≤k≤100
    输入样例1:
    3 2
    2 4 1
    输出样例1:
    2
    输入样例2:
    6 2
    3 2 6 5 0 3
    输出样例2:
    7
    样例解释
    样例1:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
    
    样例2:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4
    随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。共计利润 4+3 = 7.

    算法1
    可以参考 AcWing 1054. 股票买卖 Leetcode 121. 买卖股票的最佳时机 常规及通用DP办法

    使用一个dp[x][y][z]数组来表示某种情况下的收益情况
    x表示是第x天,y表示当前已经经过了第几次交易(交易以买进卖出两个操作为一次)
    z使用0或者1来表示当前是否持有股票。
    这样的状态有一个疑问,如果z为1,怎么知道是持有哪天的股票呢
    可以这样解决 在dp[x][y][z]的第X天中如果z不为1 则可以进行购买股票
    那么dp[x][y][z] = dp[x][y][1]-prices[i]. 从收益中减去买入的股票价格即可
    状态转移方程如下

    //当前第i天交易0次并持有股票的状态 是从前一天的交易0次持有股票转化而来
    //或者是从前一天交易0次未持有股票买进了当前的股票转化而来。
    dp[i][0][1] = max(dp[i - 1][0][1], dp[i - 1][0][0] -prices[i]);

    //当前第i天交易1次并未持有股票的状态 是从前一天交易1次未持有股票转化而来
    //或者是从前一天交易1次持有股票以当天价格卖掉状态转化
    dp[i][1][0] = max(dp[i - 1][1][0], dp[i - 1][0][1] + prices[i]);
    dp的边界和初始化

    dp[0][0][1] = -arr[0]; //第一天买入 花费了第一天股票的价格
    dp[0][0][0] = 0; //初始情况
    dp[0][1][1] = -99999999;//理论上不存在第一天就交易了一次还持有股票的情况
    dp[0][1][0] = -99999999;//理论上不存在第一天就交易了一次的情况
    扩展到卖买两次和买卖K次的限制的情况

    // acwing1057.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    
    #include <iostream>
    #include <algorithm>
    
    
    using namespace std;
    
    /*
    给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。
    
    设计一个算法来计算你所能获取的最大利润,你最多可以完成 k 笔交易。
    
    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。
    
    输入格式
    第一行包含整数 N 和 k,表示数组的长度以及你可以完成的最大交易数量。
    
    第二行包含 N 个不超过 10000 的正整数,表示完整的数组。
    
    输出格式
    输出一个整数,表示最大利润。
    
    数据范围
    1≤N≤105,
    1≤k≤100
    输入样例1:
    3 2
    2 4 1
    输出样例1:
    2
    输入样例2:
    6 2
    3 2 6 5 0 3
    输出样例2:
    7
    样例解释
    样例1:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,
    这笔交易所能获得利润 = 4-2 = 2 。
    
    样例2:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 
    这笔交易所能获得利润 = 6-2 = 4 。
    随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出,
    这笔交易所能获得利润 = 3-0 = 3 。共计利润 4+3 = 7.
    */
    
    const int N = 100010;
    const int M = 150;
    
    int arr[N];
    int n; int k;
    
    int dp[N][M][2];
    
    
    int main()
    {
        cin >> n; cin >> k;
    
        for (int i = 0; i < n; i++) {
            cin >> arr[i];
        }
    
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < 2; j++) {
                dp[0][i][j] = -9999999;
            }
        }
        dp[0][0][0] = 0;
        dp[0][0][1] = -arr[0];
    
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                if(j >0)
                    dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j-1][1]+arr[i]);
                else  dp[i][j][0] = dp[i - 1][j][0];
                dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j][0] -arr[i]);
            }
        }
    
        int ans = 0;
    
        for (int i = 0; i <= k; i++) {
            ans = max(ans, dp[n - 1][i][0]);
        }
    
        cout << ans << endl;
    
    
        return 0;
    }
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    C#多线程编程实战(一):线程基础
    查找算法之顺序查找
    设计模式01 创建型模式
    查找算法之二分查找
    设计模式01 创建型模式
    每天学一个,设计模式概要
    设计模式 01
    汽车电子传感器科普:激光雷达 毫米波雷达 超声波雷达
    C 如何判断编译器是否支持C90 C99?
    Node.js之EventEmiter
  • 原文地址:https://www.cnblogs.com/itdef/p/13496853.html
Copyright © 2011-2022 走看看