您的位置:首页 > 其它

hdu 4336 Card Collector (期望dp|容斥原理)

2014-02-12 12:05 309 查看
题意:每包里面最多只有一张卡片(可能没有),要集齐n张不同的卡片(1<=n<=20)

问集齐n张卡片要买的包数期望。

算法:

1、期望公式:E=sum(xi*pi)。等于某一件事件的状态*它发生的概率。

在高中课本里就是列个分布列然后求期望。



我们用二进制枚举卡片表示各个状态。1表示已经集齐,0表示还没有。

从末态倒推到起始状态。



这里我们看每个状态是可能由哪个状态转移而来,乘以这个转移事件发生的概率

就是当前状态得到的期望了。

要注意的是这个转移事件发生的概率的理解:

它不是输入的那个概率,而是当前可以发生的转移中正在计算的转移所占的概率。

即如果当前状态能够从n种状态转移得来,则第i种发生的概率为pi/sum(p1....pn) ,其中sum(p1...pn)

p1...pn只是m个事件的子集(可以等于)

这就是为什么要除以能发生转移的概率和的原因。也是我高中学期望的时候老是出错的地方。

2、容斥原理:

容斥原理中奇加偶减,比如:

如果被计数的事物有A、B两类,那么,A类B类元素个数总和= 属于A类元素个数+ 属于B类元素

个数—既是A类又是B类的元素个数。(A∪B = A+B - A∩B)

如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和=
A类元素个数+ B类

元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类

又是C类的元素个数+既是A类又是B类而且是C类的元素个数。(A∪B∪C
= A+B+C - A∩B - B∩C - C∩A + A∩B∩C)

然后我们知道如果一件事发生的概率为pi,那么第一次发生这件事次数期望为1/pi。

同理,a和b这两件事发生的概率为p1,p2,则第一次发生某一件事发生的次数期望为1/p1+p2

期望公式:

#include<cstdio>
#include<cstring>

double dp[1<<20],p[22];

int main()
{
    int n,tot;
    double tmp;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%lf",&p[i]);
        tot=(1<<n)-1;
        dp[tot]=0.0;
        for(int s=tot-1;s>=0;s--)
        {
            dp[s]=1;
            tmp=0.0;
            for(int j=0;j<n;j++)
            {
                if(s&(1<<j)) continue;
                dp[s]+=dp[s|(1<<j)]*p[j];
                tmp+=p[j];
            }
            dp[s]/=tmp;
        }
        printf("%lf\n",dp[0]);
    }
    return 0;
}


容斥原理:

#include <cstdio>  
#include <cstring>  
const int MAXN = 20;  
double p[MAXN];  
  
int main()  
{  
    int n;  
    while(~scanf("%d", &n))  
    {  
        for(int i=0;i<n;++i)  
        {  
            scanf("%lf", &p[i]);  
        }  
        double ans = 0.0;  
        for(int i=1;i<(1<<n);++i)  
        {  
            int cnt = 0;  
            double sum = 0.0;  
            for(int j=0;j<n;++j)  
            {  
                if(i&(1<<j))  
                {  
                    sum += p[j];  
                    ++ cnt;  
                }  
            }  
            if(cnt&1)  
            {  
                ans += 1.0 / sum;  
            }  
            else  
            {  
                ans -= 1.0 / sum;  
            }  
        }  
        printf("%lf\n", ans);  
    }  
    return 0;  
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: