爱丽丝参与一个大致基于纸牌游戏 “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
,则该答案将被视为正确答案通过。 - 此问题的判断限制时间已经减少。
这道题真的就有点难
说一下解题思路
/*
* 例如N=3,K=2,W=3 我们要求的实际是 i=[1,2,3]中,i=2的概率+i=3的概率
* 我们可以从头开始推,当手中没有牌时,你抽到1的概率是 1/3也就是dp[1]=1/w
* 当i=2时的方法有两种: 手中牌是0, 你直接抽到2 这时概率是 A=1/3=1/w
* 手中牌是1, 你抽到1 这时的概率是 B=1/3*1/3=(1/w)*(1/w) 这里用的是条件概率的算法
* 最终 dp[2]=A+B
* 因为当i<=w的时候,你是可以直接抽到一张牌符合结果的
* 所以,当i<=w的时候 dp[1]=1/w,dp[2]=dp[1]*1/w+1/w,dp[3]=dp[1]*1/w+dp[2]*1/w+1/w ... dp[i] = sum(dp[1,i-1])/w+1/w
* 当i>w的时候没有办法取一次得到结果,所以不用加上1/w了,例如:N=6,K=4,W=2
* 当i=3时,有2种取法1+2,2+1 没有办法从0直接到3,也就没有1/w了
* dp[1]=1/w,dp[2]=dp[1]/w+1/w,dp[3]=sum(dp[1,2])/w
* 当i=4时有两种取法2+2,3+1 , dp[4]=sum(dp[2,3])/w=(sum(dp[1,3])-dp[1])/w=(sum(dp[w+1,i])-dp[i-w])/w
* 因为i的最大值是N所以dp的长度就是N+1
* 最终解为sum(dp[K,N])
* 而当N >=(K + W)时 所有种k和w的和都不会超出N所以解是 1
*/
#include <iostream>
using namespace std;
double new21Game(int N, int K, int W) {
int i;
double dp[10002];
double sum = 0;
dp[0] = 1;
if(K > 0){
sum = sum + 1;
}
for(i = 1; i <= N; i++){
dp[i] = sum / W;
if(i < K){
sum += dp[i];
}
if(i >= W){
sum -= dp[i - W];
}
}
double ans = 0;
for(i = K; i <= N; i++){
ans += dp[i];
}
return ans;
}
int main(){
double re = new21Game(21, 17, 10);
cout << re << endl;
}