HDU-4336 Card Collector

           Card Collector

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2421    Accepted Submission(s): 1140
Special Judge


Problem Description
In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award.

As a smart boy, you notice that to win the award, you must buy much more snacks than it seems to be. To convince your friends not to waste money any more, you should find the expected number of snacks one should buy to collect a full suit of cards.
 

 

Input
The first line of each test case contains one integer N (1 <= N <= 20), indicating the number of different cards you need the collect. The second line contains N numbers p1, p2, ..., pN, (p1 + p2 + ... + pN <= 1), indicating the possibility of each card to appear in a bag of snacks.

Note there is at most one card in a bag of snacks. And it is possible that there is nothing in the bag.
 

 

Output
Output one number for each test case, indicating the expected number of bags to buy to collect all the N different cards.

You will get accepted if the difference between your answer and the standard answer is no more that 10^-4.
 

 

Sample Input
1
0.1
2
0.1 0.4
 

 

Sample Output
10.000
10.500
 

题意:每包里面最多只有一张卡片(可能没有),要集齐n张不同的卡片(1<=n<=20)

问集齐n张卡片要买的包数期望。

算法:

1、 期望公式 :E=sum(xi*pi)。等于某一件事件的 状态 *它发生的概率。

在高中课本里就是列个分布列然后求期望。

      

我们用二进制枚举卡片表示各个状态。1表示已经集齐,0表示还没有。

从末态倒推到起始状态。

      

这里我们看每个状态是可能由哪个状态转移而来,乘以这个转移事件发生的概率

就是当前状态得到的期望了。

要注意的是这个转移事件发生的概率的理解:

它不是输入的那个概率,而是当前可以发生的转移中正在计算的转移所占的概率。

即如果当前状态能够从n种状态转移得来,则第i种发生的概率为pi/sum(p1....pn) ,其中sum(p1...pn)

p1...pn只是m个事件的子集(可以等于)

这就是为什么要除以能发生转移的概率和的原因。也是我高中学期望的时候老是出错的地方。

2、 容斥原理 :

容斥原理中奇加偶减

 ,比如:

 

如果被计数的事物有A、B两类,那么,A类B类元素个数总和= 属于A类元素个数+ 属于B类元素

 

个数—既是A类又是B类的元素个数。(A∪B = A+B - A∩B) 

 

如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类

 

元素个数+C类元 素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类

 

又是C类的元素个数+既是A类又是B类而且是C类的元素个数。(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)

 

然后我们知道如果一件事发生的概率为pi,那么第一次发生这件事次数期望为1/pi。

 

同理,a和b这两件事发生的概率为p1,p2,则第一次发生某一件事发生的次数期望为1/p1+p2

如果一个事件发生的概率为p, 那么它第一次发生时的次数期望就是1/p

    1:     1/p 
    2:    (1-p)*p
    3:    (1-p)^2*p
    ......
    n:    (1-p)^(n-1)*p

    以上求和,用错位相消的方法求出 E = 1/p

    类似的,我们可以得出 如果两个事件发生的概率分别为p1,p2, 那么
    第一次发生其中的某一件的次数期望就是1/(p1+p2)。

    根据这个结论我们就可以用容斥原理来做这题了。
#include<stdio.h>
double f[20];
int main()
{
  int n,j,cnt,i;
   double sum,ans;
  while(~scanf("%d",&n))
  {
       ans=0;
     for(i=1;i<=n;i++)
       scanf("%lf",&f[i]);
     for(i=1;i<1<<n;i++)
     {
           cnt=0;
           sum=0;
         for(j=1;j<=n;j++)
         {
           if(i&1<<(j-1))
              {
                  sum+=f[j];
                   cnt++;
              }
         }
         if(cnt%2==1)
            ans+=1.0/sum;
         else
           ans-=1.0/sum;
    }
     printf("%lf
",ans);
  }
  return 0;
}


状态压缩:

#include<cstdio>
#include<cstring>

double dp[1<<20],p[22];

int main()
{
    int n,tot;
    double tmp;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%lf",&p[i]);
        tot=(1<<n)-1;
        dp[tot]=0.0;
        for(int s=tot-1;s>=0;s--)
        {
            dp[s]=1;
            tmp=0.0;
            for(int j=0;j<n;j++)
            {
                if(s&(1<<j)) continue;
                dp[s]+=dp[s|(1<<j)]*p[j];
                tmp+=p[j];
            }
            dp[s]/=tmp;
        }
        printf("%lf
",dp[0]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cancangood/p/3904928.html