UVA - 11181 Probability|Given (条件概率+全排列算法枚举集合)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/80721069

题目大意:n个人去买东西,其中第i个人买了东西的概率是p[i],已知恰有m个人买了东西,问每个人买了东西的概率。

思路:设“恰有m个人买了东西”的概率是P1,“恰有m个人买了东西,并且第i个人买了东西”的概率是P2,根据条件概率公式易知在恰有m个人买了东西的条件下,第i个人买了东西的概率是P2/P1,设P1为tot,P2为sum[i],只需枚举所有“恰有m个人买了东西”时的情况。对于每种情况,计算出该情况发生的概率P,把tot加上P。如果这时第i个人恰好也在买了东西的m个人之中,则把sum[i]也加上P。最终的结果就是sum[i]/tot。

代码实现可以用递归的方法,不过较为复杂而且容易出错。好在C++有自带的全排列算法next_permutation,可以利用这个算法,创建一个只含01的长度为n的vis数组,用vis[i]=0表示第i个人不买东西,vis[i]=1表示第i个人买了东西。首先把vis数组的后m位初始化为1,其余的初始化为0,然后用next_permutation就可以枚举出所有的情况来了,简单粗暴。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define FRER() freopen("i.txt","r",stdin)
using namespace std;
const int N=20+2;
int vis[N],n,m,kase=1;
double p[N],tot,sum[N],P;

int main()
{
    //FRER();
    while(scanf("%d%d",&n,&m)&&n)
    {
        fill(sum,sum+n,0);
        tot=0;
        for(int i=0; i<n; ++i)
        {
            scanf("%lf",&p[i]);
            vis[i]=i<n-m?0:1;
        }
        do
        {
            P=1;
            for(int i=0; i<n; ++i)
                P*=vis[i]?p[i]:1-p[i];
            tot+=P;
            for(int i=0; i<n; ++i)
                if(vis[i])
                    sum[i]+=P;
        }
        while(next_permutation(vis,vis+n));
        printf("Case %d:\n",kase++);
        for(int i=0; i<n; ++i)
            printf("%f\n",sum[i]/tot);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/80721069
今日推荐