• HDU 4336 Card Collector


    题意:

         在每包小当家方便面里面,可能有一张卡片,也可能没有。已知有总共有n张卡片,第i张的卡片出现的可能是pi。 问收集齐所有的卡片需要吃方便面数的期望是多少。

    先来讲一下期望这个东西。

    E的原始定义是E=p1*x1+p2*x2+... pi表示买xi包面能集齐所有卡片的概率。从实际上说,买n*E包方便面(n非常大),极大可能得到n套卡片。

    从理论上说,在理想的情况下,买E包方便面,必然得到1套卡片

    先把问题简化一下,只有一张卡片,其发生的概率是p,集齐这张卡片需要吃方便面的期望是E.

     则 E=p*1+(1-p)*(1+E).

    虽然把这个公式化简成Ep=1比较好理解,但是要写出多张卡片,就必须先理解 E=p*1+(1-p)*(1+E).

    那么定义p为只买了一张卡片,就集齐一套卡片。则(1-p)为买了多张卡片(第一张失败)就集齐一套卡片。这两个事件是对立的。

    那么对于买了多张卡片集齐一套卡片中多张卡片是几张呢,(1+E), 理论上说是必然。

    对于两张卡片,设(00)表示还未集齐所有卡片到集齐所有卡片(11)需要购买方便面的期望是E(00)。

                         (10)表示已经集齐第一张卡片,到集齐所有卡片(11)需要构面方便面的期望是E(00)

        E(00)=p1*(1+E(10))                                   //买了第一包面摸到了第1张卡片,概率是p1,接下来还需要E(10)包方便面

           +p2*(1+E(01))                                 //买了第一包面摸到了第2张卡片,概率是p1,接下来还需要E(01)包方便面

                        +(1-p1-p2)(1+E(00))                      ////买了第一包面,里面什么也没有,概率是1-p1-p2,接下来还需要E(00)包方便面

                E(01)=p1*(1+E(11)) +(1-p1-p2) *(1+E(01))

         E(10)=p2*(1+E(11))+(1-p1-p2)*(1+E(10))

        E(11)=0  //已经集齐了,当然只要买0包方便面就行了。

    所以对于n张卡片。 x 是一个二进制数

      E(x)=∑(pi*(1+E(y))+(1-∑pi)*(1+E(x))      i表示x的第i位等于0.y表示讲x的第i位从0变成1以后的二进制数。

        解一下方程 E(x)=(1+∑(pi*E(y)))/(∑pi)

                     这就是概率动态规划的状态转移方程了。

                    E(1111111..n个1)=0  ,临界状态。

           E(00000...n个0) =?  目标状态。

    这里是非递归写法,从111..循环减1。

    #include <stdio.h>
    #include <string.h>
    double f[2000000];
    int main()
    {
        int i,j,m,n;
        double p[100];
        while (scanf("%d",&n)!=EOF)
        {
            for (i=1; i<=n; i++)
                scanf("%lf",&p[i]);
            int s=0;
            for (i=0; i<n; i++)
                s=s*2+1;
            f[s]=0;
            for (i=s-1; i>=0; i--)
            {
                m=i;
                double fenmu=0,fenzi=0;
                for (j=0; j<n; j++)
                {
                    if (m%2==0)
                    {
                        fenmu+=p[n-j];
                        fenzi+=(p[n-j]*f[i+(1<<(j))]);
                    }
                    m/=2;
                }
                f[i]=(1.0+fenzi)/fenmu;
    
            }
            printf("%lf
    ",f[0]);
        }
        return 0;
    }
    

      

  • 相关阅读:
    super().__init__()方法
    so the first day
    left join,right join,inner join,full join之间的区别
    C#中几种常用的集合的用法ArrayList集合HashTable集合List<T>集合Dictionary<K,V>集合及区别
    C#中Dictionary<string,string>的初始化 两种方式不同
    C#中Dictionary的初始化方式
    如何批量修改文件后缀名?cmd命令 ren *.gif *.jpg
    eclipse查看一个方法被谁引用(调用)的快捷键四种方式
    C# 数组集合
    Java-数组和集合简单使用
  • 原文地址:https://www.cnblogs.com/six-god/p/3580242.html
Copyright © 2020-2023  润新知