状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1;
F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了。
1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6 { 7 while (scanf("%d",&n)!=EOF) 8 { 9 double Sum=0; 10 for (int i=1;i<=n;i++) scanf("%lf",&p[i]),Sum+=p[i]; 11 F[0]=0; Sum=1-Sum; //Sum表示为空的概率. 状态位为1表示该张卡片还未取. 12 for (int i=1;i<(1<<n);i++) 13 { 14 double X=0,Ret=0; 15 for (int j=1;j<=n;j++) 16 { 17 if (!(i&(1<<(j-1)))) X+=p[j]; 18 else Ret+=p[j]*F[i^(1<<(j-1))]; 19 } 20 X=X+Sum; 21 F[i]=(Ret+1)/(1-X); 22 } 23 printf("%.5lf\n",F[(1<<n)-1]); 24 } 25 return 0; 26 }
容斥原理: 若发生的概率为p,第一次发生的概率的期望是1/p,我感觉并不是很显然。
Prove:E=p+p(1-p)*2+p*(1-p)^2*3+...=pS
S=1+(1-p)*2+(1-p)^3..=1/p^2
∴Ep=1
那么两个发生的期望就为1/(p1+p2)
三个发生的期望为1/(p1+p2+p3)
1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6 { 7 while (scanf("%d",&n)!=EOF) 8 { 9 double Ans=0; 10 for (int i=1;i<=n;i++) scanf("%lf",&p[i]); 11 for (int i=1;i<(1<<n);i++) 12 { 13 double Sum=0; int cnt=0; 14 for (int j=1;j<=n;j++) 15 if (i&(1<<(j-1))) 16 { 17 Sum+=p[j]; 18 cnt++; 19 } 20 if (cnt&1) Ans+=1/Sum; else Ans-=1/Sum; 21 } 22 printf("%.5lf\n",Ans); 23 } 24 return 0; 25 }