股票买卖V

股票买卖V

题目描述

image-20210220161000658


核心思路

最大利润f是天数i的函数,每天有两个状态,手中有票和手中无票。对于无票,我们又可细分为无票的第1天(刚卖出股票)、无票的第2天(冷冻期)、$\cdots 、无票的第 、无票的第 、无票的第x$天。

状态表示:

  • f [ i ] [ 1 ] f[i][1] f[i][1]表示第i天手中有票,所能获取的最大利润。
  • f [ i ] [ 0 ] f[i][0] f[i][0]表示第i天是手中无票的第1天(即刚卖出股票的第1天),所能获取的最大利润。
  • f [ i ] [ 2 ] f[i][2] f[i][2]表示第i天是手中无票的第2天及以后,所能获取的最大利润。

带权的有向图,表示状态边权表示转移的价值增量

入口只有一个,是 f [ i ] [ 2 ] f[i][2] f[i][2],因为刚开始我肯定是没有票的,因此入口不可能是 f [ i ] [ 1 ] f[i][1] f[i][1],那么就只能从无票中进入了,但是从状态图中可以看出, f [ i ] [ 0 ] f[i][0] f[i][0]只能从 f [ i ] [ 1 ] f[i][1] f[i][1]转移过来,由于我们知道 f [ i ] [ 1 ] f[i][1] f[i][1]不可能是入口了, 那么就不可能转移到 f [ i ] [ 0 ] f[i][0] f[i][0],因此,入口就只能是 f [ i ] [ 2 ] f[i][2] f[i][2]了;但是出口有两个,但必须是无票状态,即 f [ n ] [ 0 ] f[n][0] f[n][0] f [ n ] [ 2 ] f[n][2] f[n][2]

状态计算:

  • f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 2 ] − w [ i ] ) f[i][1]=max(f[i-1][1],f[i-1][2]-w[i]) f[i][1]=max(f[i1][1],f[i1][2]w[i])
  • f [ i ] [ 0 ] = f [ i − 1 ] [ 1 ] + w [ i ] f[i][0]=f[i-1][1]+w[i] f[i][0]=f[i1][1]+w[i]
  • f [ i ] [ 2 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 2 ] ) f[i][2]=max(f[i-1][0],f[i-1][2]) f[i][2]=max(f[i1][0],f[i1][2])

处理边界初值:

我们的有效天数是从第1天到第n天,边界初值一般是不包含在有效天数中的。因此,我们需要对第0天做边界初值。 f [ 0 ] [ 1 ] f[0][1] f[0][1]表示第0天手中有票,所能获取的最大利润。但是由实际含义可知,第0天不可能有票,是不合法的,那么我们给它设置为负无穷大。 f [ 0 ] [ 0 ] f[0][0] f[0][0]表示第0天是手中无票的第1天,也就是刚卖出股票的第1天,由实际含义可知,第0天不可能会有票,更不可能说能卖出股票了,因此是不合法的,那么我们给它设置为负无穷大。 f [ 0 ] [ 2 ] f[0][2] f[0][2]表示第0天是手中无票的第2天及以后,那么手中无票,肯定没有收益,所以设置为0。

image-20210220162511981

由于第i天都是从前i-1天转移过来的,现在考虑能不能把状态0和状态2合并看作一个新的状态0呢?即此时只有状态1和状态0:

如下图所示,

分析对于状态1有两种情况:

  • 从昨天第i-1天转移到今天第i天,即我今天并没有卖掉股票,所以我手中仍然有票
  • 第i-2天表示前天,第i-1天表示昨天,第i天表示今天。如果我们是从第i-1天转移过来,那么由于是状态0,所以表示第i-1天即昨天是卖出股票的第一天,那么要经过一天的冷冻期,我才能买入股票,也就是说我昨天卖出了股票,今天就不能买入股票了,因此第i-1天卖出股票,那么第i天就是冷冻期,不能买入股票。但是如果我们是从第i-2天转移过来,则表示前天卖出了股票,经过一天的冷冻期后,也就是昨天是冷冻期,那么今天就可以买入股票了,因此,是从i-2转移过来的哦。

对昨天0也是有两种情况,类似分析即可。

image-20210220185417866

状态计算:

  • f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] + w [ i ] ) f[i][0]=max(f[i-1][0],f[i-1][1]+w[i]) f[i][0]=max(f[i1][0],f[i1][1]+w[i])
  • f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 2 ] [ 0 ] − w [ i ] ) f[i][1]=max(f[i-1][1],f[i-2][0]-w[i]) f[i][1]=max(f[i1][1],f[i2][0]w[i])

边界初值:

f [ 0 ] [ 0 ] = 0 , f [ 0 ] [ 1 ] = − I N F f[0][0]=0,f[0][1]=-INF f[0][0]=0f[0][1]=INF

image-20210220190321763


代码

写法1

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,INF=0x3f3f3f3f;
//f[i][1]表示第i天手中有票,所能获取的最大利润。
//f[i][0]表示第i天是手中无票的第1天(即刚卖出股票的第1天),所能获取的最大利润。
//f[i][2]表示第i天是手中无票的第2天及以后,所能获取的最大利润。
int f[N][3];
int w[N];   //w[i]表示第i天的股票价格
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    //处理边界
    f[0][1]=f[0][0]=-INF,f[0][2]=0;
    for(int i=1;i<=n;i++)
    {
        f[i][1]=max(f[i-1][1],f[i-1][2]-w[i]);
        f[i][0]=f[i-1][1]+w[i];
        f[i][2]=max(f[i-1][0],f[i-1][2]);
    }
    printf("%d\n",max(f[n][0],f[n][2]));
    return 0;
}

写法2

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,INF=0x3f3f3f3f;
int f[N][2];
int w[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    //边界
    f[0][0]=0,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-2][0]-w[i]);
    }
    printf("%d\n",f[n][0]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心菜不卷Iris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值