Card Collector

Card Collector

有n种卡,每一卡包有概率(p_i)出现卡i,只会出现一张以下的卡,询问卡包的期望数包含所有种类的卡,(1 <= N <= 20)

法一:容斥原理

注意到数据范围很小,再此我们能很轻松地求出一种卡摸到的期望,而此时摸到的期望包含了其他的部分,于是考虑容斥。

不难有一种卡i,其摸到的期望数为(frac{1}{p_i}),而对于摸到卡i,或者j的期望数不难得知,即把它们看成一个整体(frac{1}{p_i+p_j}),于是我们可以以此为容斥依据,进行容斥即可。

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
double w[20];
int main(){
    double sxr,ans;
    int n,i,j,li,tot;
    while(scanf("%d",&n)!=EOF){
        for(i=0;i<n;++i)scanf("%lf",&w[i]);
        li=1<<n,ans=0;
        for(i=1;i<li;++i){
            tot&=0,sxr=0;
            for(j=0;j<n;++j)
                if(i>>j&1)sxr+=w[j],++tot;
            if(tot&1)ans+=1/sxr;
            else ans-=1/sxr;
        }printf("%.5lf
",ans);
    }
    return 0;
}

法二:无后效性处理

注意到为期望题,而样本空间无限大,考虑无后效性做法,即以期望代无限状态,设(E(x))表示已经摸到x对应二进制的卡种数的期望卡包数(如(E(3))表示已经摸到第1中卡和第二种卡的卡包数期望),于是不难有转移

[E(x)=1+sum E(x)p_i+sum E(y)p_j ]

其中(E(x)p_i)表示摸到已经摸过的卡,概率分别为(p_i),y则是对应二进制位已经把没摸过的卡记录下来,概率分别为(p_j)

例如,只有2种卡,设(p_0)为没有摸到任何卡的概率

[E(0)=1+E(0)p_0+E(1)p_1+E(2)p_2 ]

[E(1)=1+E(1)(p_0+p_1)+E(3)p_2 ]

[E(2)=1+E(2)(p_0+p_2)+E(3)p_1 ]

[E(3)=0 ]

于是对一般式变换一下,我们有

[E(x)=frac{1+sum E(y)p_j}{(1-sum p_i)} ]

以此为递推依据记忆化搜索即可。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int n;double w[21];
double dp[1048576];
il double search(int);
int main(){
    int i,li;
    while(scanf("%d",&n)!=EOF){
        w[n]=1;for(i=0;i<n;++i)scanf("%lf",&w[i]),w[n]-=w[i];
        memset(dp,-127,sizeof(dp)),li=(1<<n)-1,dp[li]=0;
        printf("%.5lf
",search(0));
    }return 0;
}
il double search(int er){
    if(dp[er]>=0)return dp[er];
    int i;double mom(1-w[n]),son(1);
    for(i=0;i<n;++i)
        if(er>>i&1)mom-=w[i];
        else son+=search(er|1<<i)*w[i];
    return dp[er]=son/mom;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10839273.html