ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-12-09 21:00:04  阅读:188  来源: 互联网

标签:__ 分数 骰子 ZOJ3329 19 sum Person 投掷 color


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 ) \color{cyan}e(i) e(i) 表示目前分数为 i i i , 到游戏结束时的投掷次数的期望。
  • 设 f ( i ) \color{cyan}f(i) f(i) 表示三个骰子投掷出点数和为 i i i 的概率。
  • 特别地,设 f ( 0 ) f(0) f(0) 表示投掷后,第一个骰子顶面为 a a a 面 , 第二个骰子顶面为 b b b 面, 第三个顶面骰子为 c c c 面的概率。即,每次分数归零的概率。
  • 目前分数为 i i i , 我们投掷一次之后三面骰子分别为 w 1 , w 2 , w 3 w_1,w_2,w_3 w1​,w2​,w3​
    • 下次的分数可能为 i + w 1 + w 2 + w 3 i+w_1+w_2+w_3 i+w1​+w2​+w3​,这个概率为 f ( w 1 + w 2 + w 3 ) f(w_1+w_2+w_3) f(w1​+w2​+w3​)
    • 下次的分数可能为 0 0 0 ,就是归零了,这个概率为 f ( 0 ) f(0) f(0)
  • 易得,如果已经分数超过 n n n 了,那么游戏直接结束,投掷次数期望为0,即:
    • e ( > n ) = 0 e(>n)=0 e(>n)=0
    • 我们最终的答案即为 e ( 0 ) e(0) e(0)
  • 我们写成式子就是 e ( i ) = ∑ K 1 + K 2 + K 3 k = 1 f ( k ) e ( i + k ) + f ( 0 ) e ( 0 ) + 1 \color{red}e(i)=\underset{k=1}{\overset{K_1+K_2+K_3}{\sum}} f(k)e(i+k) + f(0)e(0)+1 e(i)=k=1∑K1​+K2​+K3​​​f(k)e(i+k)+f(0)e(0)+1
  • (加一是因为多投掷了一次)
  • 注意到,我们期望是逆推的 ( i i i 从大到小),答案为 e ( 0 ) e(0) e(0),但是其中每一个递推式子都包括 e ( 0 ) e(0) e(0),这就很头疼了!

【注】如果 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}这题的套路做法 这题的套路做法

  • 设 e ( i ) = a ( i ) e ( 0 ) + b ( i ) \color{cyan}e(i)=a(i)e(0)+b(i) e(i)=a(i)e(0)+b(i)
  • 我们带入上述式子,得到:
    e ( i ) = ∑ f ( k ) e ( i + k ) + f ( 0 ) e ( 0 ) + 1 = ∑ f ( k ) ( a ( i + k ) e ( 0 ) + b ( i + k ) ) + f ( 0 ) e ( 0 ) + 1 = ( ∑ f ( k ) a ( i + k ) + f ( 0 ) ) e ( 0 ) + ( ∑ f ( k ) b ( i + k ) + 1 ) = a ( i ) e ( 0 ) + b ( i ) \begin{aligned}e(i)&=\sum f(k)e(i+k)+f(0)e(0)+1\\ &=\sum f(k)\Big( a(i+k)e(0)+b(i+k) \Big)+f(0)e(0)+1\\ &=\Big(\sum f(k)a(i+k)+f(0)\Big)e(0)+\Big( \sum f(k)b(i+k)+1 \Big)\\ &=a(i)e(0)+b(i) \end{aligned} e(i)​=∑f(k)e(i+k)+f(0)e(0)+1=∑f(k)(a(i+k)e(0)+b(i+k))+f(0)e(0)+1=(∑f(k)a(i+k)+f(0))e(0)+(∑f(k)b(i+k)+1)=a(i)e(0)+b(i)​
  • 我们得到了:
    { a ( i ) = ∑ f ( k ) a ( i + k ) + f ( 0 ) b ( i ) = ∑ f ( k ) b ( i + k ) + 1 \begin{cases} \color{red}a(i)=\sum f(k)a(i+k)+f(0)\\ \color{red}b(i)=\sum f(k)b(i+k)+1 \end{cases} {a(i)=∑f(k)a(i+k)+f(0)b(i)=∑f(k)b(i+k)+1​
  • 注意到 e ( x > n ) = a ( x ) e ( 0 ) + b ( x ) = 0 e(x>n)=a(x)e(0)+b(x)=0 e(x>n)=a(x)e(0)+b(x)=0
  • 我们得到 a ( > n ) = b ( > n ) = 0 a(>n)=b(>n)=0 a(>n)=b(>n)=0
  • 最后答案为 e ( 0 ) = a ( 0 ) e ( 0 ) + b ( 0 ) e(0)=a(0)e(0)+b(0) e(0)=a(0)e(0)+b(0),即:
  • 最终答案为 e ( 0 ) = b ( 0 ) 1 − a ( 0 ) \color{red}e(0)=\frac{b(0)}{1-a(0)} e(0)=1−a(0)b(0)​

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

核心代码

时间复杂度 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有