[ LeetCode ] 837. New 21 Game(新21点游戏)

Alice plays the following game, loosely based on the card game "21".

Alice starts with 0 points, and draws numbers while she has less than K points.  During each draw, she gains an integer number of points randomly from the range [1, W], where W is an integer.  Each draw is independent and the outcomes have equal probabilities.

Alice stops drawing numbers when she gets K or more points.  What is the probability that she has N or less points?

Example 1:

Input: N = 10, K = 1, W = 10
Output: 1.00000
Explanation:  Alice gets a single card, then stops.

Example 2:

Input: N = 6, K = 1, W = 10
Output: 0.60000
Explanation:  Alice gets a single card, then stops.
In 6 out of W = 10 possibilities, she is at or below N = 6 points.

Example 3:

Input: N = 21, K = 17, W = 10
Output: 0.73278

Note:

  1. 0 <= K <= N <= 10000
  2. 1 <= W <= 10000
  3. Answers will be accepted as correct if they are within 10^-5 of the correct answer.
  4. The judging time limit has been reduced for this question.

题意:

给定三个整数N、K、W,每一次从[1, W]区间内选择一个整数进行累计求和(假设和为sum),当sum大于等于K时停止游戏,如果游戏停止时sum小于等于N则游戏获胜,否则游戏失败。最后要求出游戏获胜的比例。

分析:

根据游戏规则,获胜时游戏的分数应该在[K,N]之间,而当分数大于N时,则游戏失败。由于游戏获胜的方式有多种,因此在计算获胜比率时,使用概率累加的方式(最终分数为[K,N]之间所有分数的概率都可以获胜)。

我们先计算出游戏最终得分为x的概率,分以下两种情况:

1) x<=W, 此时有两种选择,在[1, W]区间内可能一次抽中x 对应概率为1/W, 第二种情况分两次抽取组合最终结果为x,即第一次抽取1,2,3,4,...,i,第二次抽取x-1, x-2, x-3, x-4,..., x-i。第二种情况要保证抽取两次,所以任意一次抽取的卡片分数都要小于K(否则游戏直接终止,不需要第二次了).即 x-1

2)x>W, 此时x一定需要抽取两次及以上才能得到分数x,那么则可以在点数为x-1, x-2, x-3, ... , x-w 时选择点数分别为1,2,3,...,w的点数 即可得到结果分数x,因为此时需要保证抽取两次及以上,所以选择的分数的上线也必须小于k。

所以,递推公式可以写成如下形式:

   x <= W: dp[x] = 1/w + dp[1]/w + dp[2]/w + dp[3]/w + .... + dp[ min( x-1, k-1) ]/w. (第一个1/w为直接抽取到数值为x的概率, 其余为分两次的情况 即总数为x 时 可以是在已经抽取到的分数为1的基础之上选出x-1 那么此时概率为 dp[1] * (1/w) )。

 x > W:  dp[x] = dp[x-w]/w + dp[x-w+1]/w + dp[x-w+2]/w + ... + dp[ min (x-1, k-1)]/w. 分两种情况进行抽取。

以上递推公式最后一项的min( x-1, k-1) 均是为了保证能够抽取两次, 如果x-1大于等于k-1的话,那么此时x大于等于k 就不能继续进行第二次了。

综上所述,使用一个一维数组dp,其中dp[i]表示当目标为i时的概率,由于最后一次选择的数值范围为[i-w, i-1],这时 可选的牌有[1, w], 所以最后的点数和为[i, i-1+w], 对应我们要求得大于等于k的数,所以最后累加范围是[k, k+w-1],所以最终可以得到的结果便是dp[i](k<=i<=k+w-1)的和。

    if(K==0 || N>=K+W) return 0;    
    vector dp(N+1);
    double sum=0.0, res = 0.0;
    for(int i=1;i<=N;i++){
        if(i<=W){
            dp[i] = sum/W + 1.0/W;  // i<=W 时 分两种情况  概率相加
        }else{
            dp[i] = sum/W;    // i>W 时,一定需要抽取两次, 所以去除一次抽中的概率 即上面的1.0/w
            sum -= dp[i-W];   // 由于两次组合 并且每次抽到的数值单位是[1, w] 所以 下一步 i+1 = w + i+1-w
        }
        if(i=k 到达游戏结束条件,此时 k<=i<=N 游戏获胜的条件,因此累计获胜概率 即为最终结果。
        }
    }
    return res;

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(leetcode)