poj2151 Check the difficulty of problems

来源:互联网 发布:linux oracle启动服务 编辑:程序博客网 时间:2024/06/12 03:32

Check the difficulty of problems
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 6685 Accepted: 2907

Description

Organizing a programming contest is not an easy job. To avoid making the problems too difficult, the organizer usually expect the contest result satisfy the following two terms: 
1. All of the teams solve at least one problem. 
2. The champion (One of those teams that solve the most problems) solves at least a certain number of problems. 

Now the organizer has studied out the contest problems, and through the result of preliminary contest, the organizer can estimate the probability that a certain team can successfully solve a certain problem. 

Given the number of contest problems M, the number of teams T, and the number of problems N that the organizer expect the champion solve at least. We also assume that team i solves problem j with the probability Pij (1 <= i <= T, 1<= j <= M). Well, can you calculate the probability that all of the teams solve at least one problem, and at the same time the champion team solves at least N problems? 

Input

The input consists of several test cases. The first line of each test case contains three integers M (0 < M <= 30), T (1 < T <= 1000) and N (0 < N <= M). Each of the following T lines contains M floating-point numbers in the range of [0,1]. In these T lines, the j-th number in the i-th line is just Pij. A test case of M = T = N = 0 indicates the end of input, and should not be processed.

Output

For each test case, please output the answer in a separate line. The result should be rounded to three digits after the decimal point.

Sample Input

2 2 20.9 0.91 0.90 0 0

Sample Output

0.972
一个概率dp的题插在了哈希里.......

这道题的意思就是说现在有T只队伍,要测试的题目M然后是对冠军队伍的期望最少要解出的题目。然后就是求每只队伍至少求出一题,冠军队伍至少求出N题事件发生的概率。

不难想到,我们可以计算出,每只队伍做出1-m(用P1表示)个题的概率,然后相乘,这样就能确保结果是每支队伍都能解出1-m个题,然后还有个约束条件就是冠军队至少要解出N题,也就是说我们应当去除每支队伍都求解出1-(n-1)(用P2表示)道题的情况,这样就可以确保至少有一只队伍是求解出n道题以上的,并且其余的队伍也是至少求解出1题。

然后问题就是怎么求解出P1和P2。

我们可以先求解出每支队伍的p1和p2,然后直接相乘就可以。

然后怎么求解p1和p2。我们分别用s1,s2代替。


借用一下别人的图片,可以看的更明白一些,然后我们可以去掉第一维。

递推式就是dp[j][k]=dp[j-1][k-1]*p[i][j]+dp[j-1][k]*(1-p[i][j]);

最后计算出,前M道题分别解出1、2、3、.....M道题的概率。相加之后就得到了s1,然后P1累乘

对于P2也是一样,到N-1,得到s2,P2累乘,最后相减即可。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <cmath>#include <vector>#include <map>#include <queue>using namespace std;const int MAXN=1000+5;const int inf=0x3f3f3f;int m,t,n;double dp[35][35];double p1,p2;double p[MAXN][35];double s1,s2;int main(){    while(~scanf("%d%d%d",&m,&t,&n))    {        if(!m&&!t&&!n)break;        int i,j,k;        for(i=1; i<=t; ++i)            for(j=1; j<=m; ++j)scanf("%lf",&p[i][j]);            memset(dp,0,sizeof(dp));//初始化dp数组        p1=1.0,p2=1.0;//p1用来记录每个队伍做1-m个题的概率,p2用来记录每个队伍做1~(n-1)个题目的概率        for(i=1; i<=t; ++i)        {            dp[0][0]=1.0;//前0道题做出0个题的概率自然是0            for(j=1;j<=m;++j)dp[j][0]=dp[j-1][0]*(1-p[i][j]);//前j个题做出0道题的概率            for(j=1;j<=m;++j)//计算每个队伍的dp值            {                for(k=1;k<=j;++k)                {                    dp[j][k]=dp[j-1][k-1]*p[i][j]+dp[j-1][k]*(1-p[i][j]);                }            }            s1=0.0,s2=0.0;            for(j=1;j<=m;++j)s1+=dp[m][j];//记录这只队伍做1-m个题的概率            for(j=1;j<n;++j)s2+=dp[m][j];//和1-(n-1)个题的概率;            p1*=s1;            p2*=s2;        }         printf("%.3f\n",p1-p2);    }    return 0;}





1 0