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;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2831647.html