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;
 }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章