您的位置:首页 > 其它

poj 2151 概率dp

2015-07-29 13:55 183 查看
举办一场ACM比赛很麻烦,准备的问题不能太难(爆零会让参赛者很难受),又不能没区分度(过题数一样的队伍排名从金到铁不太好吧)。所以举办方想知道所有的队伍都至少过了1题

并且冠军至少过了一定数量的题的概率。

给出比赛总题数 M 和参赛队伍数 T 和举办方希望冠军队伍至少过题数 N。

再给出每个队伍对于每道题目通过的概率p[T][M]。

求解该概率P。

对于题目要求的概率,我们可以根据容斥原理。先求出所有队伍都过一踢以上的概率P1,然后再求出所有队伍只过了(1~n-1)的·概率P2。

根据容斥原理 P = P1 - P2。

要求P1,P2 我们先要求出每个队伍过一定数量的题目的概率。

dp[i][j]表示该队伍在前i题过了j题的概率。

我们可以很容易看出:(其中p[j] 是该队伍过 j 题的概率)

dp[i][j] = dp[i-1][j] * (1 - p[j]) + dp[i-1][j-1] * p[j];

这里我们可以进行一些空间优化:(注意循环要倒着写)

dp[j] = dp[j] * (1 - p[j]) + dp[j-1] * p[j];

这样对每个队伍都进行一遍求解,我们可以得到每个队伍过指定数量题目的概率。

dp[i][j] 表示第 i 个队伍过 j 道题目的概率。

P1 = ∏(1 - dp[i][0]); (1 <= i <= T)

P2 = ∏(Σ(dp[i][j])); (1 <= i <= T , 1 <= j < N)

于是得到答案 P = P1 - P2;

/***********************************************
 ** problem ID	: poj_2151.cpp
 ** create time	: Mon Jul 27 16:56:56 2015
 ** auther name	: xuelanghu
 ** auther blog	: blog.csdn.net/xuelanghu407
 **********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int M, T, N;
double p[1010][33];
double dp[1010][33];

int main () {
	while (cin >> M >> T >> N) {
		if (M == 0 && T == 0 && N == 0) break;
		for (int i=1; i<=T; i++) {
			for (int j=1; j<=M; j++) {
				scanf ("%lf", &p[i][j]);
			}
		}
		
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for (int i=1; i<=T; i++) {
			dp[i][0] = 1.0;
			for (int j=1; j<=M; j++) {
				for (int k=j; k>=1; k--) {
					dp[i][k] = dp[i][k] * (1.0 - p[i][j]) + dp[i][k-1] * p[i][j];
				}
				dp[i][0] = dp[i][0] * (1.0 - p[i][j]);
			}
		}
		
		double res = 1.0;
		double rec = 1.0;
		for (int i=1; i<=T; i++) {
			res *= (1 - dp[i][0]);
			double tmp = 0.0;
			for (int j=1; j<N; j++) {
				tmp += dp[i][j];
			}
			rec *= tmp;
		}
		
		printf("%.3lf\n", res - rec);  
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: