hdu - 4336 - Card Collector - 容斥 || 概率dp

http://acm.hdu.edu.cn/showproblem.php?pid=4336

题意:

给出n种不同卡片在买的小吃力里面出现的可能,求凑齐n种卡片要买的小吃的平均数量。

思路:

根据官方解题报告做的:

设卡片的分布p=(p1,p2,...,pn),T(p)表示拿到所有卡片时买的零食数目,有

由容斥原理得,

#include <cstdio>  
#include <iostream>  
using namespace std;  
  
const int maxn = 22;  
double p[maxn];  
  
int main() {  
  
   int n,i,j;  
   while (~scanf("%d",&n))  
   {  
       for (i = 0; i < n; ++i) scanf("%lf",&p[i]);  
  
       double ans = 0.0;  
       //根据二项式定理C(n,0)+C(n,1) + ... + C(n,n) = 2^n  
       //所以这里2^n - 1种可能,枚举  
       for (i = 1; i < (1<<n); ++i)  
       {  
           int ct = 0;  
           double tmp = 0.0;  
           for (j = 0; j < n; ++j)  
           {  
               if (i&(1<<j))//检查0到n中存在于i状态的点  
               {  
                   ct++;  
                   tmp += p[j];  
               }  
           }  
           //鸽巢定理  
           if (ct&1) ans += 1.0/tmp;  
           else ans -= 1.0/tmp;  
       }  
       printf("%.4lf\n",ans);  
   }  
    return 0;  
}  

状态dp:

用一个状态表示当前抽到的卡片的状况,1代表尚未拿的卡片,有d[now]=x*d[now]+sigma(si*pi*(now^(1<<i)))+1,si表示stat中该位是0还是1,x表示停留在该状态的概率,即没拿到其它卡片的概率(没抽到卡片+抽到当前已有卡片),移项可以得到d[now]=sigma(..)/(1-x)。

  #include <string.h>
  #include <stdio.h>
  int n;
  double p[25],d[1<<21];
  //d[stat] stat中为1的位表示尚未拿的卡片
  //d[now]=x*d[now]+sigma(si*pi*(now^(1<<i)))+1,si表示stat中该位是0还是1
  //移项有d[now]=sigma(..)/(1-x) x表示停留在该状态的概率,即没拿到其它卡片
  int main(){
      while(scanf("%d",&n)!=EOF){
         double tot=0;
         for(int i=0;i<n;i++){
             scanf("%lf",&p[i]);
             tot+=p[i];
         }
         tot=1-tot,d[0]=0;
         for(int i=1;i<(1<<n);i++){
             double x=0,sigma=1;
             for(int j=0;j<n;j++){
                 if(((i>>j)&1)==0)x+=p[j];
                 else sigma+=p[j]*d[i^(1<<j)];
             }
             d[i]=sigma/(1-tot-x);
         }
         printf("%.5f\n",d[(1<<n)-1]);
     }
     return 0;
 }



你可能感兴趣的:(hdu - 4336 - Card Collector - 容斥 || 概率dp)