http://poj.org/problem?id=2151
给m,m道题
t,t个队伍
n,必须有队伍ac数超过n题
求 满足以下2个条件的概率
1、所有队伍至少过1题,
2、冠军队伍至少过n题
dp[i][j][k] 表示 第i只队伍做了前j道题,过了k题
那么可以得到 dp[i][j][k]=dp[i][j-1][k-1]*(tm[i][j])+dp[i][j-1][k]*(1-tm[i][j]);
当然要预处理一下dp[i][j][0]这些边界
得到dp[i][j][k]后,可以求 s[i][k] 表示第i队做了小于等于k题的概率
//s[i][k]= dp[i][m][0]+dp[i][m][1]+...+ dp[i][m][k];
//=s[i][k-1]+dp[i][m][k];
同样要记得预处理边界 s[i][0]=dp[i][m][0];
那么最后 全部人至少作出1道题的概率是 p1=(1-s[ 1 ][0])*(1-s[ 2 ][0])*.....*(1-s[ t ][0])
全部人只做出(1至N-1)道题的概率p2= (s[1][N-1]-s[1][0])* ...*(s[i][N-1]-s[i][0])
p1-p2 得到的就是 所有人至少做出一道,并且有人至少做了n道的概率了。
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; double tm[1005][35]; int cun[1005]; double dp[1005][35][35]; double s[1005][35]; int main() { int m,t,n; while(scanf("%d%d%d",&m,&t,&n)!=EOF) { int i,j,k; if (!m&&!t&&!n) break; memset(dp,0,sizeof(dp)); memset(s,0,sizeof(s)); memset(cun,0,sizeof(cun)); for (i=1;i<=t;i++) { for (j=1;j<=m;j++) { scanf("%lf",&tm[i][j]); if (tm[i][j]>0) cun[i]++; } } int flag=0; for (i=1;i<=t;i++) { if (cun[i]>=n) flag=1; if (cun[i]==0){flag=0;break;} } if (!flag) {printf("0.000\n"); continue;} //初始化 for (i=1;i<=t;i++) { dp[i][0][0]=1; for (j=1;j<=m;j++) { dp[i][j][0]=dp[i][j-1][0] * (1-tm[i][j]); } s[i][0]=dp[i][m][0]; } for (i=1;i<=t;i++) { for (j=1;j<=m;j++) { for (k=1;k<=j;k++) { dp[i][j][k]=dp[i][j-1][k-1]*(tm[i][j])+dp[i][j-1][k]*(1-tm[i][j]); } } } //s[i][k]第i队做了不超过k题的概率 //s[i][k]= dp[i][m][0]+dp[i][m][1]+...+ dp[i][m][k]; //=s[i][k-1]+dp[i][m][k]; for (i=1;i<=t;i++) { for (j=1;j<=m;j++) { s[i][j]=s[i][j-1]+dp[i][m][j]; } } double p1=1; double p2=1; for (i=1;i<=t;i++) { p1*=(1-s[i][0]); p2*=s[i][n-1]-s[i][0]; } printf("%.3lf\n",p1-p2); } return 0; }