愛麗絲參與一個大致基於紙牌遊戲 “21點” 規則的遊戲,描述如下:
愛麗絲以 分開始,並在她的得分少於 K 分時抽取數字。 抽取時,她從 的範圍中隨機獲得一個整數作爲分數進行累計,其中 是整數。 每次抽取都是獨立的,其結果具有相同的概率。
當愛麗絲獲得不少於 分時,她就停止抽取數字。 愛麗絲的分數不超過 的概率是多少?
示例 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
提示:
如果答案與正確答案的誤差不超過 ,則該答案將被視爲正確答案通過。
此問題的判斷限制時間已經減少。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/new-21-game
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
題解
因爲最終的概率是和下一輪開始前的得分有關的,因此我們可以根據得分計算下面的概率。
設表示得分爲的情況下開始玩遊戲並且獲勝的概率。那麼就可以確定所需要的求的答案是。
根據題意,當分數大於等於的時候遊戲結束,如果遊戲結束的時候,如果分數不超過就獲得勝利。如果分數超過就失敗。那麼當
這是因爲不超過K的時候能夠最大的數字是,此時可以抽一次,最大值爲,所以得到的最大分數爲
那麼當的時候。每一個得分可以轉移個狀態,因爲在的狀態下可以抽取的範圍爲,每個數字的概率爲。所以可以表示爲:
所以根據這個狀態轉移方程,可以計算出最後的答案,但是我們會發現,這個狀態轉移的時間複雜度有點高。
但是一般動態規劃都是相鄰項之間的轉移,那麼我們看看相鄰項之間的關係。
所以可以得到了
其中
注意的取值範圍哦,所以我們需要單獨處理。
因此我們可以在的範圍內得到轉移方程。
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]
}