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(BiA)=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;
}

你可能感兴趣的:(UVA - 11181 Probability|Given(条件概率+状压dfs))