愛麗絲參與一個大致基於紙牌遊戲 “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 = 10 的 6 種可能下,她的得分不超過 N = 6 分。
示例 3:
輸入:N = 21, K = 17, W = 10
輸出:0.73278
提示:
- 0 <= K <= N <= 10000
- 1 <= W <= 10000
- 如果答案與正確答案的誤差不超過 10^-5,則該答案將被視爲正確答案通過。
- 此問題的判斷限制時間已經減少。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/new-21-game
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
基本思想
這道題當初的思想是枚舉所有的結果,並統計次數;並計算結果中不超過N的次數,二者相比求概率。這個思想的錯誤在於:每一種組合並不是等概率出現的。
例如:K = 3, N = 3, W = 2。對於 1,2 和1,1,2,這兩種情況出現的概率不相等前者出現的概率是1/4,後者是1/8.
動態規劃:
- dp[i]:當前分數爲 i 時,獲勝的概率。也就是說,當前抽取的和爲 i ,再抽取一張有多大概率能獲勝。那麼最終結果就是dp[0]
- i 的範圍:i 最小爲0,最大爲 K - 1 + W(也就是當前和爲K - 1,還能在抽取一次,再抽取一次的結果最大是W)
- 初始值:當i >= K 且 i < = N時,dp[i] = 1;當 i >= K且i > N時,dp[i] = 0。(說明:N和K-1+W的大小關係是不確定的,如果N>=K-1+W最終結果一定是1)
- 狀態轉移方程:當前爲i的情況下,抽取每一張牌的概率爲1/W,獲勝的概率爲其對應的dp值
- 代碼中,狀態轉移方程需要求當前元素後面W項的和,用sum來計算
class Solution {
public:
double new21Game(int N, int K, int W) {
//定義dp
//dp[i]:當前得分爲i的情況下,分數不超過N的概率
//i最大爲:K—1+W
if(K - 1 + W <= N)//當累計的最終結果的最大值不超過N,最終概率爲1
return 1;
vector<double> dp(K + W, 0);
//初始化:當前得分>=K,分數不超過N的概率爲1,因爲無需再抽取數字
for(int i = K; i < K + W && i <= N; ++i)
dp[i] = 1;
double sum = N - K + 1;//初始時,1的個數
for(int i = K - 1; i >= 0; --i){
dp[i] = sum / W;
sum = sum + dp[i] - dp[i + W];
}
return dp[0];
}
};