POJ 2151 Check the difficulty of problems:概率dp【至少】

题目链接:http://poj.org/problem?id=2151

题意:

  一次ACM比赛,有t支队伍,比赛共m道题。

  第i支队伍做出第j道题的概率为p[i][j].

  问你所有队伍都至少做出一道,并且有队伍做出至少n道的概率。

 

题解:

  关于【至少】问题的表示。

  

  对于每一支队伍:

    mst[i][j] = P(第i支队伍做出至多j道题)

    则 P(第i支队伍做出至少j道题) = 1 - mst[i][j-1]

  

  对于所有队伍:

    P(所有队伍至少答出一题) = ∏ (1 - mst[i][0])

    P(所有队伍答题数在1到n-1) = ∏ (mst[i][n-1] - mst[i][0])

    所以答案:

    P(所有队伍至少答出一题,且有队伍做出至少n道) = P(所有队伍至少答出一题) - P(所有队伍答题数在1到n-1)

 

  所以求mst数组好啦~~~

  dp[i][j][k] = probability

  i:第i支队伍

  j:考虑到前j道题(包含j)

  k:恰好做出k道

  所以 mst[i][j] = sigma(dp[i][m][0 to j])

 

  怎么求dp数组呢:

    转移:dp[i][j][k] = dp[i][j-1][k-1]*p[i][j] + dp[i][j-1][k]*(1-p[i][j])

    边界:dp[i][0][0] = 1, others = 0

 

  所以这道题:先求dp,再求mst,最后统计ans。

 

AC Code:

  1 // state expression:
  2 // dp[i][j][k] = probability
  3 // i: ith team
  4 // j: jth question and before
  5 // k: solved k questions
  6 // mst[i][j]
  7 // i: ith team
  8 // j: all the teams solved at most j questions
  9 //
 10 // find the answer:
 11 // P(all 1 to m) - P(all 1 to n-1)
 12 //
 13 // transferring:
 14 // dp[i][j][k] = dp[i][j-1][k-1]*p[i][j] + dp[i][j-1][k]*(1-p[i][j])
 15 //
 16 // boundary:
 17 // dp[i][0][0] = 1
 18 // others = 0
 19 //
 20 // calculate:
 21 // mst[i][j] = sigma dp[i][m][0 to j]
 22 // P1 = pi (1 - mst[i][0])
 23 // P2 = pi (mst[i][n-1] - mst[i][0])
 24 //
 25 // step:
 26 // 1) cal dp
 27 // 2) cal mst
 28 // 3) cal ans
 29 #include <iostream>
 30 #include <stdio.h>
 31 #include <string.h>
 32 #define MAX_T 1005
 33 #define MAX_N 35
 34 #define MAX_M 35
 35 
 36 using namespace std;
 37 
 38 int n,m,t;
 39 double p1,p2;
 40 double p[MAX_T][MAX_M];
 41 double dp[MAX_T][MAX_M][MAX_M];
 42 double mst[MAX_T][MAX_M];
 43 
 44 void read()
 45 {
 46     for(int i=1;i<=t;i++)
 47     {
 48         for(int j=1;j<=m;j++)
 49         {
 50             cin>>p[i][j];
 51         }
 52     }
 53 }
 54 
 55 void cal_dp()
 56 {
 57     memset(dp,0,sizeof(dp));
 58     for(int i=1;i<=t;i++)
 59     {
 60         dp[i][0][0]=1;
 61         for(int j=1;j<=m;j++)
 62         {
 63             for(int k=0;k<=m;k++)
 64             {
 65                 if(k-1>=0) dp[i][j][k]+=dp[i][j-1][k-1]*p[i][j];
 66                 dp[i][j][k]+=dp[i][j-1][k]*(1-p[i][j]);
 67             }
 68         }
 69     }
 70 }
 71 
 72 void cal_mst()
 73 {
 74     // mst[i][j] = sigma dp[i][m][0 to j]
 75     memset(mst,0,sizeof(mst));
 76     for(int i=1;i<=t;i++)
 77     {
 78         for(int j=0;j<=m;j++)
 79         {
 80             for(int k=0;k<=j;k++)
 81             {
 82                 mst[i][j]+=dp[i][m][k];
 83             }
 84         }
 85     }
 86 }
 87 
 88 void cal_ans()
 89 {
 90     // P1 = pi (1 - mst[i][0])
 91     // P2 = pi (mst[i][n-1] - mst[i][0])
 92     p1=1.0;
 93     p2=1.0;
 94     for(int i=1;i<=t;i++)
 95     {
 96         p1*=(1-mst[i][0]);
 97         p2*=(mst[i][n-1]-mst[i][0]);
 98     }
 99 }
100 
101 void solve()
102 {
103     cal_dp();
104     cal_mst();
105     cal_ans();
106 }
107 
108 void print()
109 {
110     printf("%.3f\n",p1-p2);
111 }
112 
113 int main()
114 {
115     while(cin>>m>>t>>n)
116     {
117         if(m==0 && t==0 && n==0) break;
118         read();
119         solve();
120         print();
121     }
122 }

 

posted @ 2017-09-16 03:18  Leohh  阅读(179)  评论(0编辑  收藏  举报