hdu 4336 Card Collector (期望dp|容斥原理)

来源:互联网 发布:迅雷9网络诊断工具 编辑:程序博客网 时间:2024/05/02 20:45

题意:每包里面最多只有一张卡片(可能没有),要集齐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


期望公式:

#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\n",dp[0]);    }    return 0;}


容斥原理:

#include <cstdio>  #include <cstring>  const int MAXN = 20;  double p[MAXN];    int main()  {      int n;      while(~scanf("%d", &n))      {          for(int i=0;i<n;++i)          {              scanf("%lf", &p[i]);          }          double ans = 0.0;          for(int i=1;i<(1<<n);++i)          {              int cnt = 0;              double sum = 0.0;              for(int j=0;j<n;++j)              {                  if(i&(1<<j))                  {                      sum += p[j];                      ++ cnt;                  }              }              if(cnt&1)              {                  ans += 1.0 / sum;              }              else              {                  ans -= 1.0 / sum;              }          }          printf("%lf\n", ans);      }      return 0;  }  









0 0
原创粉丝点击