uva 11181 Probability|Given

数学题(概率基础题+暴力)

题意:给你n个人,给出每个人会购物的概率,然后给你r,即r个人会购物其余人都不购物。然后需要你输出n行,第i行就是这个r个人中有一个是第i个的概率是多少

其原型就是,有5个人,选3个人出来,甲在其中的概率。不过5变成了n,3变成了r。这个样子的话就是一个条件概率

即pb为从n个人中选r个的概率。pa就是甲在其中的概率   pa/pb就是答案

这个样的话,只能暴力了(我只能想到暴力),即在n个人中找出r个人(就是一个组合,不是排列),把这r个人的概率相乘其余人的反面概率相乘。然后所有的这些我概率相加就是pb。然后同样的,选定甲,再选r-1个人(组合),甲和这r-1个人的概率相乘,其余人的反概率相乘,然后相加就是pa

 

这两个过程是可以合并在一起的

然后主要说一下怎么构建组合,我用的方法是递归构建,而且是增序构建,这样才能区别组合和排列

好像123是一个组合,123,132,312,231…………这些是排序,不能算进去会重复,所以就要求增序,显然123只有123这种唯一情况

然后就看代码吧,怎么把算pa和pb的过程合并,看了代码应该都会明白了

 

#include <cstdio>

#include <cstring>

#define N 25

double p[N],ans[N],pb,pa;

int a[N],n,r,tot;



void add()

{

    int vis[N];

    double tmp=1;

    //printf("第%d次枚举\n",++tot);

    //for(int i=1; i<=r; i++) 

        //printf("%d ",a[i]); 

    //printf("\n");



    memset(vis,0,sizeof(vis));

    for(int i=1; i<=r; i++)

    {

        vis[a[i]]=1;  //标记

        tmp*=p[a[i]];

    }

    for(int i=1; i<=n; i++) 

        if(!vis[i])

            tmp*=(1-p[i]);

    //printf("tmp=%.6f\n",tmp);



    for(int i=1; i<=r; i++)

        ans[a[i]]+=tmp;



    pb+=tmp;

}

void dfs(int c , int pre)  //c是还要再找c个人,pre是前面人的编号

{

    if(c<=0)  //找完r个人

    {

        add();

        return ;

    }

    for(int i=pre+1; i<=n-c+1; i++) //当前可能枚举的人

    {

        a[r-c+1]=i;

        dfs(c-1,i);

    }

    return ;

}

void get_pb_pa()

{

    /*

    先用递归枚举r个不同的买东西的人,用增序枚举就不会重复,把r个人编号保存下来

    每次递归到第r层也就是枚举结束了,就进去一个处理函数

    处理函数把这r个人的概率相乘,再和其余人的反概率相乘

    只要枚举完所有可能的r个人,那么就得到了pb也就是“只有r个人购物的概率”

    */

    pb=0; 

    tot=0;  //tot只是个用于测试的变量

    dfs(r,0);

    //printf("pb=%.6f\n",pb);

}

int main()

{

    int Case=0;

    while(scanf("%d%d",&n,&r)!=EOF)

    {

        if(!n && !r) break;

        for(int i=1; i<=n; i++) scanf("%lf",&p[i]);

        memset(ans,0,sizeof(ans));

        get_pb_pa();  //单独一个函数计算pb和所有的pa

        printf("Case %d:\n",++Case);

        for(int i=1; i<=n; i++)

            printf("%.6f\n",ans[i]/pb);

        

    }

    return 0;

}

 

你可能感兴趣的:(uva)