买卖股票问题
能否当天买入当天卖出
有时候题目规定,不可以当天买入当天卖出。但我们一般情况下不必考虑这个,只需要将 \(res\) 初始化为 \(0\),确保利润不可能为负数即可。
1. 只能买卖一次
贪心选择买入时机,枚举卖出时机。
2. 可以买卖无限次
线性 \(DP\):\(f[i][j]\):
\(j=0\) :在第 \(i\) 天买入时的最大利润
\(j=1\) :在第 \(i\) 天卖出时的最大利润
3. 含手续费
每次卖出时额外减去手续费即可。
4. 含冷冻期
线性 \(DP\):买入时,必须通过前一天的卖出来转移。
5. 最多买卖 \(k\) 次
线性 \(DP\):\(f[i][j][k]\):
\(f[i][j][0]\):在第 \(i\) 天,第 \(j\) 次交易,买入时的最大利润
\(f[i][j][1]\):在第 \(i\) 天,第 \(j\) 次交易,卖出时的最大利润
另外就是注意初始化问题,这里的初始化比较复杂?
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10, M = 110, INF = 0x3f3f3f3f;
int n, k, w[N];
// f[i][j][0]:在第i天,第j次交易,买入时的最大利润
// f[i][j][1]:在第i天,第j次交易,卖出时的最大利润
int f[2][M][2]; // 滚动数组优化
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) cin >> w[i];
// 这里的初始化主要是处理i=0以及j=0的情况
// 由于我们求的是最大值,因此这里要初始化为最小值
// (1)对于卖出的情况,我们可以当天买入当天卖出,因此最大利润至少为0
// (2)对于买入的情况,由于第0天不存在,买入不合法,因此我们应该将其初始化为最小值
// 不过特殊的,对于j=0时,交易不存在,可以理解为既没有买入也没有卖出,此时最大利润应该为0
for(int i = 1; i <= k; i ++ ) f[0][i][0] = -INF;
int res = 0;
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= k; j ++ )
{
// 0: 买入股票
f[i & 1][j][0] = max(
// 上一次就持有股票 or 这一次购入
f[(i - 1) & 1][j][0], f[(i - 1) & 1][j - 1][1] - w[i]
);
// 1:卖出股票
f[i & 1][j][1] = max(
// 上一次就未持有股票 or 这次卖了
f[(i - 1) & 1][j][1], f[(i - 1) & 1][j][0] + w[i]
);
res = max(res, f[i & 1][j][1]);
}
}
cout << res << endl;
return 0;
}