题解 | #买卖股票的最好时机(三)#

买卖股票的最好时机(三)

http://www.nowcoder.com/practice/2fea2b0349df4f7689f6f5a882e4f129

动态规划----多阶段决策过程

  • 阶段 1:第一次买之前
  • 阶段 2:持有股票(第一次买之后,但还没卖)
  • 阶段 3:第一次卖之后且第二次买之前
  • 阶段 4:持有股票(第二次买之后,但还没卖)
  • 阶段 5:第二次卖之后

在这种情况下,如果今天想买股票,需要知道前一天处于什么阶段。

如:前一天处在“阶段 2”,那今天就有两种可能的决策:

  • 1、卖掉前一天买入的股票,不买。----> 进入阶段 3
  • 2、卖掉前一天买入的股票,立即买入----> 进入阶段 4

如果前一天处在“阶段 3”,则今天只能买 或者 不买:

  • 买 ----> 进入阶段 4
  • 不买 ----> 停在阶段 3

此题最优策略一定是前N天结束后,处于

  • 阶段 1: 没买卖过
  • 阶段 3: 买卖 1 次
  • 阶段 5: 买卖 2 次

因为如果持有股票不卖,不能获利,而本题要求获利最大,因此不能处在阶段 3 和 阶段 4。

例如1:在第N天(前 N-1 天结束)处在阶段 5 的最大获利为: dp[N][5]

  • 情况 1: 前一天已经处在阶段 5 了,那今天就不用动,获利跟前一天一样,前一天在阶段 5的最大获利为: dp[N-1][5]

  • 情况 2: 前一天处在阶段 4(第二次持有股票),那今天就卖掉股票,进入阶段 5,则今天的获利:

    dp[N][5] = dp[N-1][4] + (P[N-1] - P[N-2])

    即:前一天所处阶段的最大获利 + 持有的股票的利润(每多持有一天,就多一天的红利(可能为负))

同上,例如2,在阶段 4的最大获利,dp[N][4]

  • 情况 1: 前一天已经处在阶段 4,则今天的获利为:dp[N-1][4] + (P[N-1] - P[N-2])--括号里为今天的红利
  • 情况 2: 前一天处在阶段 3,因为当前处于阶段 4,所以是今天刚买,刚买还没有红利,所以其获利为:dp[N-1][3]
  • 情况 3: 前一天还在阶段 2,今天直接卖掉立马买入而进入阶段 4,则获利为:dp[N-1][2] + (P[N-1] - P[N-2])

初始条件: 刚开始 第0天处于阶段1,

  • dp[0][1] = 0
  • dp[0][2] = dp[0][3] = dp[0][4] = dp[0][5] = -float('inf')

状态转移方程:

  • 对于阶段 1、3、5(例如1):

    dp[i][j] = max{dp[i-1][j], dp[i-1][j-1] + (P[N-1] - P[N-2])}

  • 对于阶段 2、4(例如2):

    dp[i][j] = max{dp[i-1][j] + (P[N-1] - P[N-2]), dp[i-1][j-1], dp[i-1][j-2] + (P[N-1] - P[N-2])}

  • 注意:若下标越界成了负号,则不计入max项。又因为最多买卖2次,所以最大获利一定是清仓状态,即:

    max{dp[N][1], dp[N][3], dp[N][5]}

下面附上代码:


import sys

inputs = []
for line in sys.stdin:
    a = line.split()
    inputs.append(a)
    
n = int(inputs[0][0])
P = [int(x) for x in inputs[1]]

dp = [[0] * (5 + 1) for _ in range(n + 1)]

# 初始条件
dp[0][1] = 0
dp[0][2] = dp[0][3] = dp[0][4] = dp[0][5] = -float('inf')

for i in range(1, n + 1):
    # 1, 3, 5
    for j in (1, 3, 5):
        # dp[i][j] = max{dp[i-1][j], dp[i-1][j-1] + (P[N-1] - P[N-2])}
        dp[i][j] = dp[i-1][j]
        if j > 1 and i >= 2 and dp[i-1][j-1] != -float('inf'):
            dp[i][j] = max(dp[i][j], dp[i-1][j-1] + (P[i-1] - P[i-2]))
    
    # 2, 4
    for j in (2, 4):
        # dp[i][j] = max{dp[i-1][j] + (P[N-1] - P[N-2]), dp[i-1][j-1], dp[i-1][j-2] + (P[N-1] - P[N-2])}
        dp[i][j] = dp[i-1][j-1]
        if i > 1 and dp[i-1][j] != -float('inf'):
            dp[i][j] = max(dp[i][j], dp[i-1][j] + (P[i-1] - P[i-2]))
            
        if j > 2 and i >= 2 and dp[i-1][j-2] != -float('inf'):
            dp[i][j] = max(dp[i][j], dp[i-1][j-2] + (P[i-1] - P[i-2]))
    
print(max(dp[n][1], dp[n][3], dp[n][5]))
    
全部评论

相关推荐

评论
5
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务