原题连接:leetcode-cn.com/problems/ne…
题目:
爱丽丝参与一个大致基于纸牌游戏 “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,则该答案将被视为正确答案通过。
- 此问题的判断限制时间已经减少。
题解:
首先,我们来理解一下题目。这个题目第一眼看完,感觉好像不是很明白他的意思,后来明白,其实是要计算爱丽丝玩这个游戏的胜率。
我们先一步步来看这个游戏的规则:
① 爱丽丝每次翻一张牌,牌的点数最大为W,最小为1,每次抽牌后,需要将牌放回牌池,所以每次抽到点数的概率是相同的,即1\W。
② 当爱丽丝的总得分大于K时,爱丽丝必须停止抽牌
③ 当爱丽丝停止抽牌时,总得分大于N则被判定失败,总得分小于等于N则被判定为胜利
④ 求 当给定K W和N时,爱丽丝获胜的概率是多少
刚分析完题目时,并没有想到用dp来求解,后来琢磨了一下,我们一起来看一下。
假设dp(x)为当爱丽丝手中的点数为x时,爱丽丝获胜的概率。
我们拿示例3来举例,可以看到,K为17,也就是说,爱丽丝在当x=16时,一定是最后一次抽牌,因为不论抽到多大的点数,爱丽丝都必须停止抽牌。所以我们假设现在x为16。
由于dp(17)至dp(26)时,爱丽丝已停止抽牌,所以这时,胜负是确定的,即当x为K至x为K+W-1时,胜负是确定的。17/18/19/20/21时为胜,22/23/24/25/26时为负,所以此时爱丽丝的胜率为5\10。
所以我们可以得到[dp(k),dp(k+w-1)]
for(var i=K;i<K+W;i++){
dp[i] = i>N?0:1;//当手上的牌点数为i时获胜的概率
}//状态转移方程:
//知:若x<=K-1,dp[x] = (dp[x+1]+dp[x+2]+dp[x+3]+……+dp[x+W])/W;
//则,dp[x+1] = (dp[x+2]+dp[x+3]+dp[x+4]+……+dp[x+W+1])/W;
//dp[x]-dp[x+1] = ((dp[x+1]+dp[x+2]+dp[x+3]+……+dp[x+W])-(dp[x+2]+dp[x+3]+dp[x+4]+……+dp[x+W+1]))/W;
//dp[x]-dp[x+1] = (dp[x+1]-dp[x+W+1])/W;
//dp[x] = (dp[x+1]-dp[x+W+1])/W+W*dp[x+1]/W;
//dp[x] = (dp[x+1]-dp[x+W+1]+W*dp[x+1])/W;
//dp[x] = ((W+1)*dp[x+1]-dp[x+W+1])/W;
//所以,状态转移方程为dp[x] = ((W+1)*dp[x+1]-dp[x+W+1])/W;
由于dp[K-1]在我们求[dp(k),dp(k+w-1)]时就可以得到,并且如果将K-1套入方程,dp[x+W+1]无法求得,这里做了一个优化,在求dp[x+W+1]时,就先把dp[K-1]求得,后面直接从dp[k-2]开始计算。
得到状态转移方程,直接套公式求解即可
/**
* @param {number} N
* @param {number} K
* @param {number} W
* @return {number}
*/
var new21Game = function(N, K, W) {
var dp = [];
let sumNum = 0;
for(var i=K;i<K+W;i++){
dp[i] = i>N?0:1;
sumNum += dp[i];
}
dp[K-1] = sumNum/W;
for(var i=K-2;i>=0;i--){
//直接套入公式 dp[i] = ((W+1)*dp[i+1]-dp[i+W+1])/W;
}
return dp[0];
};