UVA - 11181 Probability|Given(条件概率+状压dfs)
题目链接
设事件 A A A为: m m m个人买了东西,事件 B i B_i Bi为:第 i i i个人买了东西。显然要求的是条件概率 P ( B i ∣ A ) = P ( A B i ) P ( A ) P(B_i|A)= \frac{P(AB_i)}{P(A)} P(Bi∣A)=P(A)P(ABi)
求 P ( A ) P(A) P(A)就是 n n n个人里面恰好有 m m m个状态为 1 1 1,那么我们考虑状压搜索;而 P ( A B i ) P(AB_i) P(ABi)是两事件同时发生的概率,那么就是满足 P ( A ) P(A) P(A)的合法状态里将每个为 1 1 1的人对应的 P ( A B i ) P(AB_i) P(ABi)累积,这样最后就能求出每个人的条件概率了
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <cstdio>
#include <string>
#include <bitset>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> P;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int Mod=1e9+7;
const int maxn=2e5+10;
int n,m;
double sum;
bool vis[1<<21];
int num[1<<21];
double p[25],ans[25];
int cal(int x){ //计算x中有多少1
int cnt=0;
while(x){
if(x&1) cnt++;
x>>=1;
}
return cnt;
}
double solve(int x){ //计算状态x(例如10110)对应的概率
double res=1.0;
int y=x;
for(int i=0;i<n;i++){
if(x&1) res*=p[i];
else res*=1.0-p[i];
x>>=1;
}
for(int i=0;i<n && y;i++){ //将其中状态为1的位的P(AB)加上当前概率
if(y&1) ans[i]+=res;
y>>=1;
}
return res;
}
void dfs(int s){
if(vis[s]) return;
vis[s]=1;
if(num[s]>m) return;
if(num[s]==m){
sum+=solve(s);
return;
}
for(int i=0;i<n;i++) if(!(s&(1<<i))){
dfs(s|(1<<i));
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
for(int i=0;i<(1<<20);i++)
num[i]=cal(i);
int kase=0;
while(~scanf("%d%d",&n,&m) && n){
for(int i=0;i<n;i++) scanf("%lf",&p[i]);
memset(vis,0,sizeof vis);
memset(ans,0,sizeof ans);
sum=0.0; //sum不要忘记初始化
dfs(0);
printf("Case %d:\n",++kase);
for(int i=0;i<n;i++)
printf("%.6f\n",ans[i]/sum);
}
return 0;
}