zoukankan      html  css  js  c++  java
  • dice 概率论 概率DP

    题目链接:

    http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1010&cid=459

    找出公式,公式有实际意义,某种情形当重复做n次实验时会出现一次,即出现的概率为1/n,现在要想出现这种情形,平均要做多少次实验,显然平均要做n次。

    说一个具体的,比如掷色子,有6个点,6个点随机等概率出现。掷一次色子出现1的概率为1/6,现在想掷出1来,平均要掷色子多少次,即次数的数学期望是多少。

    可以证明:

    设掷i次色子才出现1的概率为p[i],则有

    p[1] = 1/6;

    p[2] = (5/6) *(1/6);第一次没有出现

    p[3] = (5/6)^2*(1/6)

    `````

    p[n] = (5/6)^n-1*(1/6);前n-1次没有出现

    ``````

    所以次数的数学期望为sum(k*p[k]),(k>=1,k为自然数,可以取到无穷)  ,据观察,有p[i] = p[i-1]*(5/6);

    式子1:s = 1*p[1] + 2*p[2] + ``` +n*p[n] +````

    式子2:(5/6)*s =     1*p[1] + ````(n-1)*p[n]+````(式子2为式子1的左右两边同时乘以5/6得到)

    用式子1-式子2得

    (1/6)*s = 1/6 + (1/6)*(5/6) + (1/6)*(5/6)^2````+(1/6)*(5/6)^n+```

    又等比数列的公式得(1/6)*s =( 1/6(1 -(5/6)^n)/(1-5/6).由于n为正无穷,所有(5/6)^n =0;所以s = 6.

    这个题的公式为:

    情形1,出现连续n个相同后停止掷色子的次数的期望 = 1+m+m^2 + ``` + m^(n-1);

    情形2,出现连续n个不同后停止掷色子的次数的期望 = 1+m/(m-1) + m^2/((m-1)*(m-2))+```+m^(n-1)/((m-1)*(m-2)*```*(m-n+1));

    可以这样解释,情形1,先随便掷色子一次,后面要掷出和这个相同的期望数为m,然后仍要掷出相同的期望为m^2```

    类推,后面要掷出和这个色子同色的概率为1/m,所以次数的期望为m。第三次掷色子要和前两次相同的概率为1/(m*m),所以期望为m*m```

    其余就自己推吧···(未必对···)

    另外一种方法:概率dp,摘自杭电解题报告

    设dp[i]表示当前在 已经投掷出 i个 不相同/相同 这个状态时期望还需要投掷多少次,然后dp[i] 有如下等式:

    相同:

        //dp[0] = 1 + dp[1]

        //dp[1] = 1 + ((m-1)dp[1] + dp[2]) / m

        //dp[i] = 1 + ((m-1)dp[1] + dp[i+1]) / m

        //...

        //dp[n] = 0;

    不相同:

        //dp[0] = 1 + dp[1]

        //dp[1] = 1 + (dp[1] + (m-1) dp[2]) / m

        //dp[2] = 1 + (dp[1] + dp[2] + (m-2) dp[3]) / m

        //dp[i] = 1 + (dp[1] + dp[2] + ... dp[i] + (m-i)dp[i+1]) / m

        //...

        //dp[n] = 0; 

    。。于是可以高斯消元。。对于第一问。。我们发现就是相当于 Typing Monkey 问题中字符串是 AAAA..AA 这一特殊情况。。解得递推式:

    dp[n] = 0

    dp[n-1] = dp[n] * m + 1

    。。。

    解开后等于等比数列求和。

    (也可以直接得到这个公式。。。因为在当前状态只有 m/1 的概率可以进入下一状态,否则要重新来过。。而这一步会另总的步数 + 1。)

    对于第二问。。

    现在设s[i]=sigma{dp[i], 1..i},对s[i] 列方程
    每个方程是关于三个相邻的s[i] 的,然后就可以线性时间解出来了。

    也可以设 d[i] = dp[i] - dp[i+1].

    可以得到 d[i] =  m * d[i-1]  / (m-i)

    然后就是解一元一次方程... 

    参见:

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=13614

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=21631

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24402

    http://www.cnblogs.com/ch3656468/archive/2011/05/04/2036332.html

    上面的两种递推式肯定能推出上面的公式来,所以我直接用公式写的

    贴代码:

     1 #include <cstdio>
     2 int main()
     3 {
     4 //    freopen("in.c","r",stdin);
     5     int t;
     6     while(scanf("%d",&t) != EOF)
     7     {
     8         while(t--)
     9         {
    10             double flag,m,n;
    11             scanf("%lf%lf%lf",&flag,&m,&n);
    12             double ans=1,tmp =1;
    13             if(flag == 0)
    14             {
    15                 for(int i=1; i<n; ++i)
    16                 {
    17                     tmp *= m;
    18                     ans += tmp;
    19 
    20                 }
    21             }
    22             else
    23             {
    24                 for(int i=1; i<n; ++i)
    25                 {
    26                     tmp *= (m/(m-i));
    27                     ans += tmp;
    28                 }
    29             }
    30             printf("%lf
    ",ans);
    31         }
    32     }
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    31天重构学习笔记28. 为布尔方法命名
    .NET 技术社区之我见(中文篇)
    31天重构学习笔记26. 避免双重否定
    31天重构学习笔记25. 引入契约式设计
    31天重构学习笔记20. 提取子类
    31天重构学习笔记18. 使用条件判断代替异常
    31天重构学习笔记19. 提取工厂类
    31天重构学习笔记24. 分解复杂判断
    31天重构学习笔记23. 引入参数对象
    31天重构学习笔记17. 提取父类
  • 原文地址:https://www.cnblogs.com/allh123/p/3246500.html
Copyright © 2011-2022 走看看