<—点个赞吧QwQ
宣传一下算法提高课整理{:target=”_blank”}
给定一个长度为 $N$ 的数组,数组中的第 $i$ 个数字表示一个给定股票在第 $i$ 天的价格。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 $1$ 天)。
输入格式
第一行包含整数 $N$,表示数组长度。
第二行包含 $N$ 个不超过 $10000$ 的正整数,表示完整的数组。
输出格式
输出一个整数,表示最大利润。
数据范围
$1 \\le N \\le 10^5$
输入样例:
5
1 2 3 0 2
输出样例:
3
样例解释
对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出],第一笔交易可得利润 2-1 = 1,第二笔交易可得利润 2-0 = 2,共得利润 1+2 = 3。
思路
闫氏$\text{DP}$分析法:
状态表示:$f_{i,k}$,其中$k=0/1/2$
- 集合:在前$i$天中买卖股票并且当前状态是$k$,如果$k=0$表示当前未持股,如果$k=1$表示当前持股,如果$k=2$表示当前是冷冻期
- 属性:$\max$
状态计算:
- 如果第$i$天未持股,那么既可以第$i-1$天未持股,也可以第$i-1$天冷冻期,即$f_{i,0}=\max\lbrace f_{i-1,0},f_{i-1,2}\rbrace$
- 如果第$i$天持股,那么既可以第$i-1$天持股,也可以买入股票,即$f_{i,1}=\max\lbrace f_{i-1,1},f_{i-1,0}-a_i$
- 如果第$i$天为冷冻期,那么只能第$i-1$天卖出,即$f_{i,2}=f_{i-1,1}$
- 所以状态转移方程就是
- $f_{i,0}=\max\lbrace f_{i-1,0},f_{i-1,2}\rbrace$
- $f_{i,1}=\max\lbrace f_{i-1,1},f_{i-1,0}-a_i$
- $f_{i,2}=f_{i-1,1}$
答案:
- 由于最后持股一定不是最优解,所以答案就是$\max\lbrace f_{i,0},f_{i,2}\rbrace$
来自一只野生彩色铅笔的状态机图片:
代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n;
int a[N];
int f[N][3];
int main () {
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
memset (f,-0x3f,sizeof (f));
f[0][0] = 0;
for (int i = 1;i <= n;i++) {
f[i][0] = max (f[i - 1][0],f[i - 1][2]);
f[i][1] = max (f[i - 1][1],f[i - 1][0] - a[i]);
f[i][2] = f[i - 1][1] + a[i];
}
cout << max (f[n][0],f[n][2]) << endl;
return 0;
}