地址 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; }