题意:一场ACM比赛有T支队伍参加,一共有m道题,给出每个队伍解出每一道题的可能性。求每只队伍至少解决一道题,且至少有一支队伍解决的问题数大于等于n的概率。(0 < M <= 30,1 < T <= 1000,0 < N <= M)
解法:概率DP。设d[i][j][k]表示第i支队伍,前j道题,解出k道的概率。则d[i][j][k] = d[i][j-1][k-1] * p[i][j] + d[i][j-1][k] * p[i][j]。
然后ans1 = ∏(1 - d[i][m][0])(0 <= i <= T),ans2 = ∏(d[i][m][1] + d[i][m][2] + ... + d[i][m][n-1])(0 <= i <= T),所求为ans1 - ans2。
tag:概率DP
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-11-14 23:07 4 * File Name: DP-POJ-2151.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 14 double p[1005][100], d[1005][40][40]; 15 16 int main() 17 { 18 int m, t, n; 19 while (scanf ("%d%d%d", &m, &t, &n) != EOF && m){ 20 for (int i = 0; i < t; ++ i) 21 for (int j = 1; j <= m; ++ j) 22 scanf ("%lf", &p[i][j]); 23 24 CLR (d); 25 for (int i = 0; i < t; ++ i){ 26 d[i][0][0] = 1; 27 for (int j = 1; j <= m; ++ j) 28 for (int k = 0; k <= m; ++ k){ 29 d[i][j][k] = d[i][j-1][k] * (1 - p[i][j]); 30 if (!k) continue; 31 d[i][j][k] += d[i][j-1][k-1] * p[i][j]; 32 } 33 } 34 35 double ans = 1.0; 36 for (int i = 0; i < t; ++ i) 37 ans *= (1 - d[i][m][0]); 38 double tmp = 1.0; 39 for (int i = 0; i < t; ++ i){ 40 double sum = 0.0; 41 for (int j = 1; j < n; ++ j) 42 sum += d[i][m][j]; 43 tmp *= sum; 44 } 45 ans -= tmp; 46 printf ("%.3f ", ans); 47 } 48 return 0; 49 }