n个队伍, m道题, 给出所有队伍可以做出每道题的概率, 求所有队伍做出的题数>=1并且冠军队伍做出的题数必须大于等于k。
首先, dp[i][j][k]表示第i支队伍在前j道题里做出k道题的概率, dp[i][j][k] = dp[i][j-1][k-1]*p[i][j]+dp[i][j-1][k]*(1-p[i][j]); 很容易可以推出这个式子。
s[i][j]表示第i支队伍做出j道题的概率, 那么s[i][j] = dp[i][m][j]。
另p1 = 所有队伍做出题数大于0的概率, p2 = 所有队伍做出的题数在1~k-1之间的概率, 那么最终结果就为p1-p2。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a) memset(a, 0, sizeof(a)) 4 double dp[1005][35][35], s[1005][35], p[1005][35]; 5 int main() 6 { 7 int n, m, k; 8 while(cin>>m>>n>>k) { 9 if(n+m+k==0) 10 break; 11 for(int i = 1; i<=n; i++) { 12 for(int j = 1; j<=m; j++) { 13 scanf("%lf", &p[i][j]); 14 } 15 } 16 mem(dp); 17 for(int i = 1; i<=n; i++) { 18 dp[i][0][0] = 1.0; //显然每个队伍在前0题做出0题的概率为1 19 } 20 for(int i = 1; i<=n; i++) { 21 dp[i][n][0] = 1.0; 22 for(int j = 1; j<=m; j++) { 23 dp[i][m][0] *= (1-p[i][j]); //每个队伍在前m题做出0题的概率 24 } 25 } 26 for(int i = 1; i<=n; i++) { 27 for(int j = 1; j<=m; j++) { 28 for(int k = 0; k<=j; k++) { 29 if(k) 30 dp[i][j][k] = dp[i][j-1][k-1]*p[i][j] + dp[i][j-1][k]*(1-p[i][j]); //状态转移, k=0时要特判一下 31 else 32 dp[i][j][k] = dp[i][j-1][k]*(1-p[i][j]); 33 } 34 } 35 } 36 for(int i = 1; i<=n; i++) { 37 for(int j = 0; j<=m; j++) { 38 s[i][j] = dp[i][m][j]; 39 if(j != 0) { 40 s[i][j] += s[i][j-1]; //这里我求的前缀和,后面求在1~k-1之间的概率时可以直接相减 41 } 42 } 43 } 44 double p1 = 1, p2 = 1; 45 for(int i = 1; i<=n; i++) 46 p1 *= (1-s[i][0]); 47 for(int i = 1; i<=n; i++) 48 p2 *= (s[i][k-1]-s[i][0]); 49 printf("%.3f ", p1-p2); 50 } 51 }