AcWing 1058 股票买卖 V

题目描述:

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

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为1天)。

输入格式

第一行包含整数 N,表示数组长度。

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

输出格式

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

数据范围

1≤N≤10^5

输入样例:

5
1 2 3 0 2

输出样例:

3

样例解释

对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出],第一笔交易可得利润 2-1 = 1,第二笔交易可得利润 2-0 = 2,共得利润 1+2 = 3。

分析:

首先按照普通线性DP的方法做,第i天的状态可以划分为持有股票和未持有股票,f[i][0]表示第i天未持有股票的最大收益,f[i][1]表示持有股票的最大收益。第i天未持有股票可能是第i - 1天就没持有股票,也可能是第i天卖了,故f[i][0] = max(f[i-1][0],f[i-1][1]+w[i])。第i天持有股票可能是第i-1天就持有股票,也可能是第i天买的股票,要想第i天买股票,则第i-2天必不能持股,所以 f[i][1] = max(f[i-1][1],f[i-2][0] - w[i]),边界状态是f[1][0] = 0,f[1][1] = -w[1]。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100005;
int f[N][2];
int main(){
    int n,price;
    scanf("%d%d",&n,&price);
    f[1][1] = -price;
    for(int i = 2;i <= n;i++){
        scanf("%d",&price);
        f[i][0]= max(f[i-1][0],f[i-1][1]+price);
        f[i][1] = max(f[i-1][1],f[i-2][0]-price);
    }   
    printf("%d\n",f[n][0]);
    return 0;
}

然后按照状态机的方法做,本质也是先考虑状态的划分,上一个方法我们是按第i天有没有持仓进行划分的,对未持仓进行进一步划分,分为第i天刚卖出和第i天没操作没仓位。持仓的状态含义不变。

其实状态2还可以进一步细分为还在冷冻期,即前一天才卖出,以及不在冷冻期可买入的状态,但是不论是哪个,状态2在下一天都可以转化为状态0,所以无须细分。初始状态是状态2,然后第一天可以选择继续无操作还是状态2,也可以选择买入股票转化为状态0。状态0的下一天可以继续维持状态0,也可以卖出转化为状态1,状态1的下一天不能买入,只能选择无操作继续空仓。从而得到状态转移方程为f[i][0] = max(f[i-1][0],f[i-1][2]-w[i]),f[i][1] = f[i-1][0] + w[i],f[i][2] = max(f[i-1][2],f[i-1][1])。边界状态为f[0][0] = f[0][1] = -INF表示不合法的方案,f[0][2]=0表示初始状态。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100005;
int f[N][3];
int main(){
    int n,price;
    scanf("%d",&n);
    f[0][0] = f[0][1] = -1e9;
    for(int i = 1;i <= n;i++){
        scanf("%d",&price);
        f[i][0] = max(f[i-1][0],f[i-1][2] - price);
        f[i][1] = f[i-1][0] + price;
        f[i][2]= max(f[i-1][2],f[i-1][1]);
    }   
    printf("%d\n",max(f[n][1],f[n][2]));
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值