Leetcode——837. 新21点 概率Dp

爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:

爱丽丝以 0 0 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [ 1 , W ] [1, W] [1,W] 的范围中随机获得一个整数作为分数进行累计,其中 W W W 是整数。 每次抽取都是独立的,其结果具有相同的概率。

当爱丽丝获得不少于 K K K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N N N的概率是多少?

示例 1:

输入:N = 10, K = 1, W = 10
输出:1.00000
说明:爱丽丝得到一张卡,然后停止。

示例 2:

输入:N = 6, K = 1, W = 10
输出:0.60000
说明:爱丽丝得到一张卡,然后停止。
在 W = 10 的 6 种可能下,她的得分不超过 N = 6 分。

示例 3:

输入:N = 21, K = 17, W = 10
输出:0.73278

提示:

0 ≤ K ≤ N ≤ 10000 0 \le K \le N \le 10000 0KN10000
1 ≤ W ≤ 10000 1 \le W \le 10000 1W10000
如果答案与正确答案的误差不超过 1 0 − 5 10^{-5} 105,则该答案将被视为正确答案通过。
此问题的判断限制时间已经减少。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/new-21-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

因为最终的概率是和下一轮开始前的得分有关的,因此我们可以根据得分计算下面的概率。
d p [ x ] dp[x] dp[x]表示得分为 x x x的情况下开始玩游戏并且获胜的概率。那么就可以确定所需要的求的答案是 d p [ 0 ] dp[0] dp[0]
根据题意,当分数大于等于 K K K的时候游戏结束,如果游戏结束的时候,如果分数不超过 N N N就获得胜利。如果分数超过 N N N就失败。那么当
d p [ x ] = { d p [ x ] = 1 K ≤ x ≤ min ⁡ ( N , K + W − 1 ) d p [ x ] = 0 x > m i n ( N , K + W − 1 ) dp[x] = \begin{cases}dp[x] = 1 \quad K \le x \le \min(N,K+W-1) \\ dp[x] = 0\quad x > min(N,K+W-1)\end{cases} dp[x]={dp[x]=1Kxmin(N,K+W1)dp[x]=0x>min(N,K+W1)

这是因为不超过K的时候能够最大的数字是 K − 1 K-1 K1,此时可以抽一次,最大值为 W W W,所以得到的最大分数为 K + W − 1 K+W-1 K+W1

那么当 0 ≤ x < K 0\le x < K 0x<K的时候。每一个 x x x得分可以转移 W W W个状态,因为在 x x x的状态下可以抽取的范围为 [ 1 , W ] [1,W] [1,W],每个数字的概率为 1 W \frac{1}{W} W1。所以 d p [ x ] dp[x] dp[x]可以表示为:
d p [ x ] = d p [ x + 1 ] + ⋯ + d p [ x + W ] W dp[x] = \frac{dp[x+1]+\cdots + dp[x+W]}{W} dp[x]=Wdp[x+1]++dp[x+W]

所以根据这个状态转移方程,可以计算出最后的答案,但是我们会发现,这个状态转移的时间复杂度有点高 O ( K W ) O(KW) O(KW)
但是一般动态规划都是相邻项之间的转移,那么我们看看相邻项之间的关系。

d p [ x ] = d p [ x + 1 ] + ⋯ + d p [ x + W ] W dp[x] = \frac{dp[x+1]+\cdots + dp[x+W]}{W} dp[x]=Wdp[x+1]++dp[x+W]
d p [ x + 1 ] = d p [ x + 1 + 1 ] + ⋯ + d p [ x + 1 + W ] W dp[x+1] = \frac{dp[x+1+1]+ \cdots + dp[x+1+W]}{W} dp[x+1]=Wdp[x+1+1]++dp[x+1+W]
所以可以得到了
d p [ x ] − d p [ x + 1 ] = d p [ x + 1 ] − d p [ x + W + 1 W dp[x]-dp[x+1] = \frac{dp[x+1]-dp[x+W+1}{W} dp[x]dp[x+1]=Wdp[x+1]dp[x+W+1
d p [ x ] = d p [ x + 1 ] − d p [ x + 1 ] − d p [ x + W + 1 ] W dp[x] = dp[x+1] -\frac{dp[x+1]-dp[x+W+1]}{W} dp[x]=dp[x+1]Wdp[x+1]dp[x+W+1]
其中 0 ≤ x < K − 1 0\le x0x<K1
注意 x x x的取值范围哦,所以我们需要单独处理 K − 1 K-1 K1
因此我们可以在 O ( 1 ) O(1) O(1)的范围内得到转移方程。

func min(a,b int)int {
    if a > b{
        return b
    }
    return a
}
func new21Game(N int, K int, W int) float64 {
    if K== 0{
        return 1.0
    }
    dp := make([]float64, K+W+1)
    for i:=K;i<=N && i<K+W;i++{
        dp[i] = 1.0
    }
    dp[K-1] = 1.0 * float64(min(N-K+1, W))/float64(W)
    for i:=K-2;i>=0;i--{
        dp[i] = dp[i+1] -(dp[i+W+1] -dp[i+1])/float64(W)
    }
    return  dp[0]
}

你可能感兴趣的:(Leetcode)