leetcode837. 新21点/动态规划

爱丽丝参与一个大致基于纸牌游戏 “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 = 106 种可能下,她的得分不超过 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值dp[i]=dp[i+1]+dp[i+2]+dp[i+3]++dp[i+W]Wdp[i] = \frac{dp[i+1]+dp[i+2]+dp[i+3]+…+dp[i+W]}{W}
  • 代码中,状态转移方程需要求当前元素后面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];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章