HDU - 6558 D - The Moon (概率dp)

The Moon card shows a large, full moon in the night’s sky, positioned between two large towers. The Moon is a symbol of intuition, dreams, and the unconscious. The light of the moon is dim, compared to the sun, and only vaguely illuminates the path to higher consciousness which winds between the two towers. 

Random Six is a FPS game made by VBI(Various Bug Institution). There is a gift named "Beta Pack". Mr. K wants to get a beta pack. Here is the rule. 
Step 0. Let initial chance rate qq = 2%. 
Step 1. Player plays a round of the game with winning rate pp. 
Step 2. If the player wins, then will go to Step 3 else go to Step 4. 
Step 3. Player gets a beta pack with probability qq. If he doesn’t get it, let qq = min(100%, qq + 2%) and he will go to Step 1. 
Step 4. Let qq = min(100%, qq + 1.5%) and goto Step 1. 
Mr. K has winning rate pp% , he wants to know what’s the expected number of rounds before he needs to play.

Input

The first line contains testcase number TT (TT ≤ 100). For each testcase the first line contains an integer pp (1 ≤ pp ≤ 100).

Output

For each testcase print Case ii : and then print the answer in one line, with absolute or relative error not exceeding 106106.

Sample Input

2
50
100

Sample Output

Case 1: 12.9933758002
Case 2: 8.5431270393

题意:

一个人的初始中奖率为q = 2%,他要玩若干局游戏,每轮游戏获胜的概率都为p,每轮游戏有以下三种情况:

(1)游戏获胜,可以抽一次奖,如果获奖则游戏结束。

(2)游戏获胜,可以抽一次奖,如果没有获奖则中奖概率q += 2%

(3)游戏输了,q += 1.5%

问中奖前玩游戏的期望轮数。

思路:

对上面三种情况分析,可以得出每种情况的概率:

(1)概率为p * q,游戏结束

(2)概率为p * (1 - q),q += 2%

(3)概率为(1 - p),q += 1.5%

考虑概率dp,用dp[i][j]表示在第 i 轮游戏结束后 q = j 的概率,不难发现,它只可以从第i - 1轮的两个状态q = j - 0.02和q = j - 0.015转移过来(分别对应情况2和情况3),q = j - 0.02 转移过来的概率就是 p * (1 - q),q = j - 0.015转移过来的概率是(1 - p),那么转移方程就可以写出来了:

dp[i][j] = dp[i - 1][j - 0.02] * p (1 - (j - 0.02)) + dp[i - 1][j - 0.015] * (1 - p)

推到这里我们发现,dp[i][j]表示的是第 i 轮游戏结束后 q = j 的概率啊,那怎么求出轮数的期望呢?

考虑第 i 轮结束时q = j,第i + 1轮结束游戏,(i + 1)是轮数,dp[i][j] * p * j是得到当前状态的概率,那么轮数的期望值就要加上(i + 1) * dp[i][j] * p * j

所以答案是什么呢,答案就是把所有状态的期望都加起来,第一层循环枚举游戏轮数,第二层循环枚举q值,当某一轮中所有q值对应的期望加起来都 < eps,就break

有几个需要注意的地方:

(1)状态转移方程第一维没有什么用啊,快去掉

(2)q值是小数,状态里要乘1000

(3)所有的q都是由q - 0.02和q = 0.015转移过来的吗?答:不是。q = 1可以由[1 - 0.02, 1]里的任何一个数转移过来,还可以从[1 - 0.015, 1]里的任何一个数转移过来,并且这两种转移方式相互独立,因为第一个对应情况2,第二个对应情况3。

(4)eps取1e-6就足够了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-6;
const int N = 1e3 + 10;

double dp[N];

int main() {
    int t, kcase = 0;
    double p;
    scanf("%d", &t);
    while(t--) {
        scanf("%lf", &p);
        p /= 100.0;
        for(int i = 0; i < N; ++i)
            dp[i] = 0.0;
        dp[20] = 1.0;
        double ans = 0.0;
        for(int i = 1; ; ++i) {
            double tmp = 0.0;
            for(int j = 1000; j >= 20; --j) {
                if(j == 1000) {
                    dp[j] = dp[j] * (1.0 - p);
                    for(int k = 980; k < 1000; ++k)
                        dp[j] += 1.0 * dp[k] * p * (1.0 - 1.0 * k / 1000.0);
                    for(int k = 985; k < 1000; ++k)
                        dp[j] += 1.0 * dp[k] * (1.0 - p);
                }
                else
                    dp[j] = 1.0 * dp[j - 20] * p * (1.0 - 1.0 * (j - 20) / 1000.0) + 1.0 * dp[j - 15] * (1.0 - p);
                tmp += 1.0 * (i + 1) * dp[j] * p * j / 1000.0;
            }
            ans += 1.0 * tmp;
            if(tmp < eps) break;
        }
        ans += 0.02 * p;
        printf("Case %d: %.7f\n", ++kcase, ans);
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43871207/article/details/109029331