poj2151 概率DP

题意:有T个人参加比赛,共有M道题,第 i 个人通过第 j 题的概率为 p[i][j]
求:所有人都至少做出一道题,而且第一名至少做出N道,求这个结果的概率
分析:可以知道,每个人自己是互不影响的 对于一个选手 i 前 j 道题,做出 k 道题的概率F[i][j][k] = F[i][j - 1][k - 1] * p[i][j] + F[i][j - 1][k] * (1 - p[i][j])
那么问题可以转化为:所有至少做出一道的概率(p1) - 所有选手做出的题数n >= 1 && n < N 的概率(p2)
设s[i][j]表示F[i][M][0] + F[i][M][1] + ... + F[i][M][j]
P1 = (s[1][M] - s[1][0])*(s[2][M]-s[2][0])*...*(s[T][M]-s[T][0])
P2 = (s[1][N-1] - s[1][0])*(s[2][N-1]-s[2][0])*...*(s[T][N-1]-s[T][0])
代码
    
      
#include < stdio.h >
#include
< string .h >
#include
< iostream >
using namespace std;

#define NN 33
#define TT 1003
int M, N, T;
double dp[TT][NN][NN];
double p[TT][NN];

double DP(){
int i, j, k;
memset(dp,
0 , sizeof (dp));

for (i = 1 ; i <= T; i ++ ){
dp[i][
0 ][ 0 ] = 1 ;
for (j = 1 ; j <= M; j ++ ){
for (k = 0 ; k <= j; k ++ ){
dp[i][j][k]
= dp[i][j - 1 ][k] * ( 1 - p[i][j]);
if (k != 0 ){
dp[i][j][k]
+= dp[i][j - 1 ][k - 1 ] * p[i][j];
}
}
}
}

double temp1, temp;
temp
= 1 ;
for (i = 1 ; i <= T; i ++ ){
temp1
= 0 ;
for (j = 1 ; j <= M; j ++ ){
temp1
+= dp[i][M][j];
}
temp
*= temp1;
}
double ans = temp; // p1

temp
= 1 ;
for (i = 1 ; i <= T; i ++ ){
temp1
= 0 ;
for (j = 1 ; j < N; j ++ ){
temp1
+= dp[i][M][j];
}
temp
*= temp1;
}
return ans - temp; // p1 - p2
}
int main() {
int i, j;
while (scanf( " %d%d%d " , & M, & T, & N) != EOF){
if (M == 0 && T == 0 && N == 0 ) break ;
for (i = 1 ; i <= T; i ++ ){
for (j = 1 ; j <= M; j ++ ){
scanf(
" %lf " , & p[i][j]);
}
}
printf(
" %.3lf\n " , DP());
}
return 0 ;
}

 

参考
 

你可能感兴趣的:(poj)