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