LC每日一题—#837《新21点》(dp题解)

348 阅读4分钟

原题连接: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

提示:

  1. 0 <= K <= N <= 10000 1 <= W <= 10000
  2.  如果答案与正确答案的误差不超过 10^-5,则该答案将被视为正确答案通过。
  3.  此问题的判断限制时间已经减少。

题解:

首先,我们来理解一下题目。这个题目第一眼看完,感觉好像不是很明白他的意思,后来明白,其实是要计算爱丽丝玩这个游戏的胜率。

我们先一步步来看这个游戏的规则:

① 爱丽丝每次翻一张牌,牌的点数最大为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];
};