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驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
阿里打赏 微信打赏
原文地址:https://www.cnblogs.com/itdef/p/13496853.html