【ACWing】1057. 股票买卖 IV

题目地址:

https://www.acwing.com/problem/content/1059/

给定一个长度为 N N N的数组,数组中的第 i i i个数字表示一个给定股票在第 i i i天的价格。设计一个算法来计算你所能获取的最大利润,你最多可以完成 k k k笔交易。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。

输入格式:
第一行包含整数 N N N k k k,表示数组的长度以及你可以完成的最大交易数量。第二行包含 N N N个不超过 10000 10000 10000的正整数,表示完整的数组。

输出格式:
输出一个整数,表示最大利润。

数据范围:
1 ≤ N ≤ 105 1≤N≤105 1N105
1 ≤ k ≤ 100 1≤k≤100 1k100

思路是动态规划。可以将整个买卖过程视为一个状态机接受一个输入,状态机有两个状态,分别是有股和无股,并且设 f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0]是到第 i i i天为止,一共恰好进行过 j j j次买入,并且第 i i i天结束时无股的情况下的最大利润,设 f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]是到第 i i i天为止,一共进行过 j j j次买入,并且第 i i i天结束时有股的情况下的最大利润。设 p [ i ] p[i] p[i]是第 i i i天的股价,那么就有:
1、今天的无股状态,可以由昨天无股或者昨天有股转移过来,如果昨天无股,那么最大利润是 f [ i − 1 ] [ j ] [ 0 ] f[i-1][j][0] f[i1][j][0];如果昨天有股,则是 f [ i − 1 ] [ j ] [ 1 ] + p [ i ] f[i-1][j][1]+p[i] f[i1][j][1]+p[i]
2、今天的有股状态,也可以由昨天无股或者昨天有股转移过来,如果昨天无股,那么最大利润是 f [ i − 1 ] [ j − 1 ] [ 0 ] − p [ i ] f[i-1][j-1][0]-p[i] f[i1][j1][0]p[i];如果昨天有股,则是 f [ i − 1 ] [ j ] [ 1 ] f[i-1][j][1] f[i1][j][1]
所以有: { f [ i ] [ j ] [ 0 ] = max ⁡ { f [ i − 1 ] [ j ] [ 0 ] , f [ i − 1 ] [ j ] [ 1 ] + p [ i ] } f [ i ] [ j ] [ 1 ] = max ⁡ { f [ i − 1 ] [ j − 1 ] [ 0 ] − p [ i ] , f [ i − 1 ] [ j ] [ 1 ] } \begin{cases}f[i][j][0]=\max\{f[i-1][j][0],f[i-1][j][1]+p[i]\} \\ f[i][j][1]=\max\{f[i-1][j-1][0]-p[i],f[i-1][j][1]\} \end{cases} { f[i][j][0]=max{ f[i1][j][0],f[i1][j][1]+p[i]}f[i][j][1]=max{ f[i1][j1][0]p[i],f[i1][j][1]}考虑初始条件,一开始第 0 0 0天,只有进行 0 0 0次买入并且无股的状态是合法的,利润是 0 0 0,所以 f [ 0 ] [ 0 ] [ 0 ] = 0 f[0][0][0]=0 f[0][0][0]=0,其余情况都不合法,其转移出来的状态都不能作为答案,可以令 f [ 0 ] [ 0 ] [ 1 ] = f [ 0 ] [ . > 0 ] [ 0 ] = f [ 0 ] [ . > 0 ] [ 1 ] = − ∞ f[0][0][1]=f[0][.>0][0]=f[0][.>0][1]=-\infty f[0][0][1]=f[0][.>0][0]=f[0][.>0][1]=。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 100010, K = 110;
int n, k;
int a[N], f[N][K][2];

int main() {
    
    
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> a[i];

    int res = 0;
    // 这里的优化的意思是,如果k >= n / 2,那么等价于可以进行无限次交易
    if (k >= n / 2) {
    
    
        for (int i = 2; i <= n; i++)
            res += max(0, a[i] - a[i - 1]);

        cout << res << endl;
        return 0;
    }

    memset(f, -0x3f, sizeof f);
    f[0][0][0] = 0;
    
    for (int i = 1; i <= n; i++) {
    
    
        for (int j = 0; j <= k; j++) {
    
    
            f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1] + a[i]);
            f[i][j][1] = f[i - 1][j][1];
            if (j >= 1) f[i][j][1] = max(f[i][j][1], f[i - 1][j - 1][0] - a[i]);
        }
    }

    cout << f[n][k][0] << endl;

    return 0;
}

时空复杂度 O ( N k ) O(Nk) O(Nk)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114401364