其他分享
首页 > 其他分享> > 【训练题19:概率DP】One Person Game | ZOJ3329

【训练题19:概率DP】One Person Game | ZOJ3329

作者:互联网

One Person Game | ZOJ3329

难度

6 / 10 6/10 6/10
有一说一,是一道经典概率DP题,个人感觉至少省赛题。
但是看其他博客都是随便秒过的 ???

题意

你有三个骰子,分别有 K 1 , K 2 , K 3 K_1,K_2,K_3 K1​,K2​,K3​面,每面投掷到的概率都相等,面上标号数字为 1 ∼ K i 1\sim K_i 1∼Ki​

一开始,你的分数为 0 0 0。
每轮:你同时投掷三个骰子,如果第一个骰子顶面为 a a a 面 , 第二个骰子顶面为 b b b 面, 第三个顶面骰子为 c c c 面 ,那么你的分数归零。否则,你的分数增加三个骰子的顶面的和。
如果你的分数超过 n n n,游戏结束

问你:游戏开始到游戏结束,你的投掷骰子次数的期望为多少?
要求答案误差 ∣ e p s ∣ < 1 0 − 8 |eps|<10^{-8} ∣eps∣<10−8

样例输入

组数, T T T
n   K 1   K 2   K 3   a   b   c n\ K_1\ K_2\ K_3\ a\ b\ c n K1​ K2​ K3​ a b c

2 0   2   2   2   1   1   1 0   6   6   6   1   1   1 2\\ 0\ 2\ 2\ 2\ 1\ 1\ 1\\ 0\ 6\ 6\ 6\ 1\ 1\ 1 20 2 2 2 1 1 10 6 6 6 1 1 1

样例输出

1.142857142857143 1.004651162790698 1.142857142857143\\ 1.004651162790698 1.1428571428571431.004651162790698

思路

【注】如果 e ( i ) e(i) e(i) 每一项递推式是关于 e ( x ) ∧ ( x ≥ i ) e(x)\wedge (x\ge i) e(x)∧(x≥i),我们可以把递推式子的右边的 e ( i ) e(i) e(i) 项拎出来放在左边,然后转化为一个左边只有 e ( i ) e(i) e(i) , 右边关于 e ( x ) ∧ ( x > i ) e(x)\wedge (x> i) e(x)∧(x>i)的式子,可以直接递推。

这 题 的 套 路 做 法 \color{red}这题的套路做法 这题的套路做法

其他的细节可以参考一下代码。

核心代码

时间复杂度 O ( K 1 K 2 K 3 + n 2 ) O(K_1K_2K_3+n^2) O(K1​K2​K3​+n2)

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 550;

double a[MAX];
double b[MAX];
double f[MAX];
int main()
{
    int KASE;
    while(cin >> KASE){
        while(KASE--){
            int n,k1,k2,k3,aa,bb,cc;
            cin >> n >> k1 >> k2 >> k3 >> aa >> bb >> cc;
            memset(a,0,sizeof(a));
            memset(b,0,sizeof(b));
            memset(f,0,sizeof(f));

            for(int i = 1;i <= k1;++i)
            for(int j = 1;j <= k2;++j)
            for(int k = 1;k <= k3;++k)		/// 注意算 f(x)时候不要把归零的答案算进去了
                if(i != aa || j != bb || k != cc)f[i+j+k] += 1.0 / k1 / k2 / k3;

            double f0 = 1.0 / k1 / k2 / k3;
            for(int i = n;i >= 0;--i){
                double t1 = f0,t2 = 1.0;
                for(int k = 3;i + k <= n;++k){
                    t1 += f[k] * a[i + k];
                    t2 += f[k] * b[i + k];
                }
                a[i] = t1;
                b[i] = t2;
            }
            printf("%.15f\n",b[0] / (1.0 - a[0]));
        }
    }
    return 0;
}

标签:__,分数,骰子,ZOJ3329,19,sum,Person,投掷,color
来源: https://blog.csdn.net/weixin_45775438/article/details/110939643