题目链接:https://vjudge.net/contest/373128#problem/H
题意:收集卡片,给出每一张卡片的抽取概率,问预期抽多少次才能够全部收集完
解题思路:
第一种:利用期望DP
先说一下期望的递推公式
i/n为抽到已经有的情况的概率
f[i]为当前状态,f[i+1]为下一个状态,1为代价值(无论能否成功转移都要1次机会)。
转化可以得到
本题的递推公式是这样:f[i]=∑p[ i→j ]f[ j ]+∑(1-p[ i→j ])f[ i ]+w[ i→j ]
利用二进制表示所有情况的状态,dp[i]表示从i状态到目标状态的期望值
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
double dp[1<<20];
double a[25];
int n;
int main()
{
while(scanf("%d",&n)!=EOF){
memset(dp,0,sizeof(dp));
int m=0;
double eps=1;
for(int i=0;i<n;i++){
scanf("%lf",&a[i]);
eps-=a[i];
}
m=(1<<n)-1;
double t1=0,t2=0;
for(int i=m-1;i>=0;i--){
t1=0,t2=0; //t1为抽到已有卡片的情况 t2为抽到没有卡片的概率
for(int j=0;j<n;j++){
if(!(i&(1<<j))){
t1+=a[j]*dp[i|(1<<j)];
}
else
t2+=a[j];
}
dp[i]=(t1+1)/(1-eps-t2);
}
printf("%.4f\n",dp[0]);
}
return 0;
}
第二种解法:容斥定理
即总情况E=E1+E2+E3+…-E12-E13-E23-…+E123+…-…
奇数加 偶数减
对于期望
事件一的期望:1/p1
事件一和事件二的期望:1/(p1+p2)
依次类推
这题n<=20,依然使用二进制来表示状态
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
double dp[1<<20];
double a[25];
int n;
int main()
{
while(scanf("%d",&n)!=EOF){
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++) scanf("%lf",&a[i]);
int m=(1<<n)-1;
double ans=0;
for(int i=m;i>0;i--){
int cnt=0;
double res=0;
for(int j=0;j<n;j++){
if(i&(1<<j)){
cnt++;
res+=a[j];
}
}
if(cnt%2==0)
ans-=1.0/res;
else
ans+=1.0/res;
}
printf("%.4f\n",ans);
}
return 0;
}