股票买卖系列——股票买卖 IV

题目描述

给定一个长度为 \(N\) 的数组,数组中的第 \(i\) 个数字表示一个给定股票在第 \(i\) 天的价格。

设计一个算法来计算你所能获取的最大利润,你最多可以完成 \(k\) 笔交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。

输入格式
第一行包含整数 \(N\)\(k\),表示数组的长度以及你可以完成的最大交易数量。

第二行包含 \(N\) 个不超过 \(10000\) 的正整数,表示完整的数组。

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

数据范围

\(1 \leq N \leq 105, 1 \leq k \leq 100\)


首先先分析题目,我们可以得到两个状态,一是手里有股票,二十手里没有股票。

所以我们可以定义一个\(dp[i][j][0, 1]\) 表示考虑前\(i\)天,做\(j\)次交易,这时手里有股票(1)还是没有股票(0)。

先看\(dp[i][j][0]\),这时手里没有股票,那么他有可能从两种情况转移来:

  1. 本来我有股票,但是我卖了,然后得到了\(w[i]\)的利润,那么这个状态是: \(dp[i - 1][j][1] + w[i]\)
  2. 本来我就没有股票,这次也没买,那么这个状态是: \(dp[i - 1][j][0]\)

然后从上面两种情况找最大值。

所以\(dp[i][j][0] = max(dp[i - 1][j][1] + w[i], dp[i - 1][j][0])\)


再看\(dp[i][j][1]\),这时手里有股票,那么他也有可能从两种情况转移来:

  1. 本来我没有股票,但是我买了,但是花了\(w[i]\)的钱,那么这个状态是: \(dp[i - 1][j - 1][0] - w[i]\)
  2. 本来我就有股票,这次也没卖,那么这个状态是: \(dp[i - 1][j][1]\)

然后从上面两种情况找最大值。

所以\(dp[i][j][1] = max(dp[i - 1][j - 1][0] - w[i], dp[i - 1][j][1]);\)

然后再看初始值:

\(dp[i][0][0]\)表示前\(i\)天,我做了\(0\)次交易,手里也肯定没有股票,那么\(dp[i][0][0] = 0;\)

上代码~

#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 100010
#define MAXM 110
int w[MAXN], dp[MAXN][MAXM][2];
signed main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &w[i]);
    memset(dp, 0xcf, sizeof(dp));
    for(int i = 0; i <= n; i++)
        dp[i][0][0] = 0;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j][1] + w[i]);
            dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - w[i]);
        }
    }
    int ans = 0;
    for(int i = 0; i <= m; i++)
        ans = max(ans, dp[n][i][0]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2021-08-03 15:46  Akafuyu  阅读(65)  评论(0)    收藏  举报