sgu-508 Black-white balls 概率-贝叶斯公式

题意:有n个球,其中有0、1、2...n个黑球的概率是相等的,现在从中取出L个球,p个黑球q个白球。现在问猜一个黑球的区间,使得落在这个区间的概率大于给定的一个数值。

详见代码:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int n, p, q, pri;
/* 
n个球,取出p+q个球,其中黑球p个,白球q个,要求的概率最低值为p 
设n个球中有k个黑球的事件为Ak ,设取出p+q个球中有p个黑球为事件B
题目所有概率为sum{p(Ak|B)}>=pri的k的取值区间 
p(Ak|B)不好求解,通过贝叶斯公式p(Ak|B) = p(B|Ak)*p(Ak)/p(B)其中
p(B|Ak) = C(p, k) * C(q, n-k) / C(p+q, n);
p(B) = sum( p(B|Ak) * p(Ak) ) k = 0...n;
由于有多少个黑球是等概率的,因此p(Ak)可以提出来约掉
p(Ak|B) = p(B|Ak) / sum( p(B|Ak) );
p(Ak|B) = (C(p, k) * C(q, n-k)) / sum( (C(p, t) * C(q, n-t)) ) 其中t的取值
为枚举的区间[0, n]
上式能够用来求出某个k值的概率值,由于需要枚举一个区间,那么将
这个区间的所有概率相加即可 
*/

const double eps = 1e-12;
typedef long long LL;
LL tot, seq[105];
LL c[55][55];

int sign(double x) {
    return x < -eps ? -1 : x > eps;
}

void init() { // init用来计算
    c[0][0] = 1;
    for (int i = 1; i <= 50; ++i) {
        c[0][i] = 1;
        for (int j = 1; j <= i; ++j) {
            c[j][i] = c[j-1][i-1] + c[j][i-1];
        }
    }
}

bool check(int a, int b) {
    LL x = 0;
    for (int i = a; i <= b; ++i) {
        x += c[p][i] * c[q][n-i];
    }
    return sign(100.0 * x / tot - pri) >= 0;
}

void gao() {
    tot = 0;
    for (int i = 0; i <= n; ++i) {
        tot += c[p][i] * c[q][n-i];
    }
    int rl, rr, len = 100;
    for (int i = 0; i <= n; ++i) { // 枚举区间 
        for (int j = i; j <= n; ++j) {
            if (j-i+1 >= len) continue;
            if (check(i, j)) {
                rl = i, rr = j, len = j-i+1;
            }
        }
    }
    printf("%d %d\n", rl, rr);
}

int main() {
    init();
    while (scanf("%d %d %d %d", &n, &p, &q, &pri) != EOF) {
        gao();
    }
    return 0;
} 

 

posted @ 2013-07-15 20:56  沐阳  阅读(517)  评论(0编辑  收藏  举报