【算法】leetcode 837. 新21點(理清思路,動態規劃)

問題來源

837.21點
愛麗絲參與一個大致基於紙牌遊戲 “21點” 規則的遊戲,描述如下:

愛麗絲以 0 分開始,並在她的得分少於 K 分時抽取數字。 抽取時,她從 [1, W] 的範圍中隨機獲得一個整數作爲分數進行累計,其中 W 是整數。 每次抽取都是獨立的,其結果具有相同的概率。

當愛麗絲獲得不少於 K 分時,她就停止抽取數字。 愛麗絲的分數不超過 N 的概率是多少?



示例 1:

輸入:N = 10, K = 1, W = 10
輸出:1.00000
說明:愛麗絲得到一張卡,然後停止。
示例 2:

輸入:N = 6, K = 1, W = 10
輸出:0.60000
說明:愛麗絲得到一張卡,然後停止。
在 W = 106 種可能下,她的得分不超過 N = 6 分。
示例 3:

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


提示:

0 <= K <= N <= 10000
1 <= W <= 10000
如果答案與正確答案的誤差不超過 10^-5,則該答案將被視爲正確答案通過。
此問題的判斷限制時間已經減少。


大佬解析


代碼


"""
需求分析:
    愛麗絲參與一個大致基於紙牌遊戲 “21點” 規則的遊戲,描述如下:
        愛麗絲以 0 分開始,並在她的得分少於 K 分時抽取數字。 抽取時,她從 [1, W] 的範圍中隨機獲得一個整數作爲分數進行累計,其中 W 是整數。 每次抽取都是獨立的,其結果具有相同的概率。
        當愛麗絲獲得不少於 K 分時,她就停止抽取數字。 
    愛麗絲的分數不超過 N 的概率是多少?
    
思路:
    假設 dp[x] 爲她手上牌面爲x時,能獲勝的概率,那麼這個概率應該是:dp[x]=1/w * (dp[x+1]+dp[x+2]+dp[x+3]...+dp[x+w])
    因爲抽取的牌面機會都是均等的,她能抽取的面值在 [1,W] 之間,所以將概率之和平均一下就是 dp[x] 的概率。

    強插一段解釋:
        x代表愛麗絲手上的牌面值,dp[x]代表愛麗絲手上持有的牌面值爲x時,她獲勝的概率(遊戲結束時她所持牌面值小於等於N的概率)。
        這個概率是怎麼來的?x分2種情況:

        當x>=K時,愛麗絲會停止抽牌,這個時候遊戲已經結束了,她是贏是輸也已經確定了,所以此時贏的概率要麼1,要麼0
        當x<K時,愛麗絲會繼續抽牌,抽牌是有概率的,所以她是贏是輸也有概率。
        她能抽到的牌面值在 [1,W] 之間,所以抽完後她的牌面在[x+1,x+w]之間,因爲每張牌機率均等,所以抽完後牌面在[x+1,x+w]之間的每個面值概率都是相等的,而假如我們已知當牌面是[x+1,x+w]的勝率(即dp[x+1]...dp[x+w]的值),那麼可以推導:
        dp[x]=1/w * dp[x+1]+ 1/w * dp[x+2] + 1/w * dp[x+3]...+ 1/w * dp[x+w]
        這個實際上就是動態規劃的狀態轉移方程,不過本例是反着來轉移的。
        
    x 最多能到 K-1,因爲當大於等於 K 時,愛麗絲會停止抽牌,所以當遊戲結束時,即愛麗絲停止抽牌時,她可能達到的最大牌面是 K+W-1,而一開始她的牌面是 0,所以我們用一個長度爲 K+W 的 dp 數組來保存她在所有面值下的勝率。
    最後 dp[0],也就是最開始愛麗絲還沒有抽牌,她的牌面爲 0 時的勝率,這個就是我們的答案。

"""


class Solution:
    def new21Game(self, N: int, K: int, W: int) -> float:
        dp_arr = [-1] * (K + W)
        s = 0
        for i in range(K, K + W):
            dp_arr[i] = 1 if i <= N else 0
            s += dp_arr[i]

        for i in range(K - 1, -1, -1):
            dp_arr[i] = s / W
            s = s - dp_arr[i + W] + dp_arr[i]
        return dp_arr[0]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章