数学题(概率基础题+暴力)
题意:给你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; }