AcWing 1055. 股票买卖 II DP

题目传送门

一、状态机模型DP解法
我这里直接贴出闫氏DP分析法的思维导图

AcWing 1055. 股票买卖 II DP

具体的状态机模型分析如下图:

AcWing 1055. 股票买卖 II DP

一共只\(2\)有种状态:

  1. 当前处于未持股状态\(0\):
    对应可以进行的转换:
    \(0->0\) (不买入,继续观望,那么就什么都不发生)
    \(0->1\) (买入股票,那么收益就要减去当前市场的股票价格)

  2. 当前处于持股状态\(1\):
    对应可以进行的转换:
    \(1->1\) (不卖出,继续观望,那么就什么都不发生)
    \(1->0\) (卖出股票,那么收益就要加上当前市场的股票价格)

二、状态机代码I

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
int w[N];
int f[N][2];//考虑前i天的股市,第i天的手中股票状态为j(j=0 未持股,j=1 持股)

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> w[i];
    //base case
    f[1][0] = 0;
    f[1][1] = -w[1];
    for (int i = 2; i <= n; i++) {
        f[i][0] = max(f[i - 1][0], f[i - 1][1] + w[i]);
        f[i][1] = max(f[i - 1][1], f[i - 1][0] - w[i]);
    }
    printf("%d\n", f[n][0]);
    return 0;
}

三、状态机代码II

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
int w[N];
int f[N][2];//考虑前i天的股市,第i天的手中股票状态为j(j=0 未持股,j=1 持股)

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> w[i];
    /**
    因为f[0][1]代表考虑前0天,状态是已经买入,这是一个不合法状态。(一般不合法的状态设置为INF或者-INF,要看取最大值或最小值)
    第一次买入至少是在第1天。
    如果不把它初始化为负无穷,f[1][0]就会更新成f[0][1] + w[1],也就是w[1]
    但是f[1][0]实际意义是第 1 天不买入股票,那么收益就是 0,而不是w[i]
    */
    f[0][1] = -INF;
    for (int i = 1; i <= n; i++) {
        f[i][0] = max(f[i - 1][0], f[i - 1][1] + w[i]);
        f[i][1] = max(f[i - 1][1], f[i - 1][0] - w[i]);
    }
    printf("%d\n", f[n][0]);
    return 0;
}

代码I和代码II的区别在于base case,也就是初始值的设定,这个需要从题意出发,理解边界情况,比如本题,第\(1\)天是开始,如果第1天过后,手中没有股票,表示为\(f[1][0]\),由于没有买入,所以收益还是\(0\),即\(f[1][0]=0\)

如果第\(i\)天过后,手中有股票,表示为\(f[1][1]\),由于买入消耗了钱,所以收益是\(-w[1]\),即\(f[1][1]=-w[i]\),然后从第\(2\)天开始进行递推。

代码II的思路也是一种常见的思路:就从第\(1\)天开始递推,那么\(1\)依赖的是前面的第\(0\)天,可是没有第\(0\)天啊!\(f[0][0]\)代表开始前一天手中没有股票,这是一种正常的现象,自然收益是\(0\),\(f[0][1]\)就是一种奇怪的状态了,没开始,手中还有了股票,这不是见鬼了吗?是一种不合法状态,一般不合法状态初始化为\(inf\)或者\(-inf\),视取最大值还是最小值而定。

上一篇:IDDD 实现领域驱动设计-CQRS(命令查询职责分离)和 EDA(事件驱动架构)


下一篇:清理SYSAUX表空间