poj2151 Check the difficulty of problems(概率dp)

版权声明:本文为博主原创文章,转载请说明出处。 https://blog.csdn.net/xianpingping/article/details/83246265

Check the difficulty of problems

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 8865   Accepted: 3760

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 2
0.9 0.9
1 0.9
0 0 0

Sample Output

0.972

Source

这道题的题意就是:

t支队伍,m道题,n

第i行第j列的数字代表第i个人出了j题的概率,求每个队至少出1题,并且冠军队至少出n道题的概率。

思路:

每个队至少出一道题的概率很好求,那么这个概率一定包含冠军队没有出n道的情况,那么我们就剪掉都只出了1~n-1道题的概率不就可以了。

这样的话,状态转移方程:

dp[i][j][k]代表第i支队伍在前j道题中,出了k道题的概率。

dp[i][j][k]=dp[i][j-1][k]*(1-a[i][j])+dp[i][j][k-1]*a[i][j];

然后对于第i支队伍来说,出了1—n-1道题的概率就是:dp[i][m][1]+dp[i][m][2]+...+dp[i][m][n-1].

然后一共有i支队伍,再乘起来。

p1-p2就是结果

代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int m,t,n;
double a[1030][31];
double dp[1030][40][40];
double sum[1030];
int main()
{
    while(scanf("%d%d%d",&m,&t,&n)!=EOF){
    if((m==0 && t==0) &&(n==0) )
    break;
    for(int i=1;i<=t;i++){
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    }
    ///先算所有一道题都不做的概率:
    double ans1=1.0;
    for(int i=1;i<=t;i++){
        double temp=1;
        for(int j=1;j<=m;j++)
        {
            temp*=(1-a[i][j]);
        }
        ans1*=(1-temp);
    }
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
    /*dp[1][0][0]=1;
    dp[1][0][1]=0;
    */
    for(int i=1;i<=t;i++){
        dp[i][0][0]=1;
        dp[i][0][1]=0;
    }
    for(int i=1;i<=t;i++){///i个人
        for(int j=1;j<=m;j++){///j门课
            for(int z=0;z<=j;z++){///当前选了z门课了
                dp[i][j][z]=dp[i][j-1][z-1]*a[i][j]+dp[i][j-1][z]*(1-a[i][j]);
            }
        }
    }
    for(int i=1;i<=t;i++){
          for(int k=1;k<=n-1;k++)
            sum[i]+=dp[i][m][k];
    }
    double p2=1;
    for(int i=1;i<=t;i++){
        p2*=sum[i];
    }
    printf("%.3lf\n",ans1-p2);
    }
}
/*
2 2 2
0.9 0.9
1 0.9
*/

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/83246265