问题描述
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少?
示例 1:
输入:N = 10, K = 1, W = 10
输出:1.00000
说明:爱丽丝得到一张卡,然后停止
解题报告
(1) 在 i
不超过 w
的前提下, 爱丽丝取得分数 i
的可能情况为:
- 最后一次抽到
1
加上爱丽丝取得分数i-1
的各种情况; - 最后一次抽到
2
加上爱丽丝取得分数i-2
的各种情况 ……
- 最后一次抽到
i-1
加上爱丽丝取得分数1
的各种情况; - 最后一次抽到
i
加上爱丽丝取得分数0
的各种情况;
(2) 当 i
超过 w
时,爱丽丝取得分数 i
的可能情况为:
- 最后一次抽到
1
加上爱丽丝取得分数i-1
的各种情况; - 最后一次抽到
2
加上爱丽丝取得分数i-2
的各种情况 ……
- 最后一次抽到
w-1
加上爱丽丝取得分数i-w+1
的各种情况; - 最后一次抽到
w
加上爱丽丝取得分数i-w
的各种情况;
(3) 由于爱丽丝获得不少于 K
分时,停止抽取数字,所以,
当 i
超过 K
时,爱丽丝取得分数 i
的可能情况为:
- 爱丽丝取得分数
K-1
加上最后一次抽到i-K+1
- 爱丽丝取得分数
K-2
加上最后一次抽到i-K+2
……
- 爱丽丝取得分数
2
加上最后一次抽到i-2
- 爱丽丝取得分数
1
加上最后一次抽到i-1
dp[i]
表示获取分数 i
的概率。具体实现看代码。
实现代码
class Solution {
public:
double new21Game(int n, int k, int w) {
if(k==0)return 1;
if(n==0||k>n)return 0;
vector<double>dp(n+1,0.0);
// dp[i]表示的是当总分为i的时候的概率,最终的答案一定是k<=i<=n的所有概率之和,表示的是当取到分数大于k小于n的概率
double sum=1.0;
double res=0.0;
dp[0]=1.0;
for(int i=1;i<=n;i++){
dp[i]=1.0*sum/w;
if(i<k){
sum+=dp[i];
}else{
res+=dp[i];//表示当前选的点是符合要求的,那么将其加入到符合条件的概率当中
}
if(i>=w){
sum-=dp[i-w];//sum表示的是中间只能有w个数据,
}
}
for(int i=0;i<dp.size();i++)cout<<dp[i]<<" ";
cout<<endl;
return res;
}
};
参考资料
[1] Leetcode 837. 新21点
[2] 题解区:zb121