【POJ 2151】Check the difficulty of problems

【POJ 2151】Check the difficulty of problems

明明是道概率dp 训练计划里却赤果果放在了hash+二分里。。。。shenmegui
不过强行把概率dp给整了出来。。自己瞎捣鼓居然捣鼓出来了
T支队伍每支队伍都要解M道题 问每只队伍至少解1道并且解答最多的队伍要解N道以上的概率是多少
直接做很难 可以用补集
P(AllTeam >= 1 && MaxTeam >= N) = 1 - P(HasTeam < 1 || AllTeam < N)
开一个数组 存放对应解题数的概率

for i 1->T                                 //第i队伍
{
     for j 1->M                            //第j题
     {
        for k j->0                         //j限制了最大解题数 
            if(k==0) dp[k] *= (1-p[j]);    //1题没解 = 1-p[j]累乘
            else dp[k] = dp[k]*(1-p[j]) + dp[k-1]*p[j]
    }
}

dp后分别找出HasTeam<1 || AllTeam < N的概率即可求出答案
我们发现 两边存在重叠 可以合并为P(HasTeam < 1) + P(0 < AllTeam < N)
0 < AllTeam < N 就是所有队伍1~N+1的所有组合乘积
假设T = 2 N = 4
team1解决1题概率为a 解决两题为b 三题为c
team2解决1题概率为A 解决两题为B 三题为C
显然 P(0 < AllTeam < N) = a*A + b*A + c*A + a*B + b*B + c*B + a*C + b*C + c*C = (a+b+c)*(A+B+C)
同样对于多个队伍来说也是如此 故可推出 P(0 < AllTeam < N) = 每只队伍各自解1~n-1个题的累加 然后把每只队伍各自的加和累乘
求P(HasTeam < 1)又会发现 如果和上面一样求法会出现重叠 p1*p2在后面又会出现p2*p1 所以同样再用一次补集 P(HasTeam < 1) = 1 - P(NoTeam < 1)
P(NoTeam < 1) = team 1->T (1-dp[0])累乘
准备工作都做完后便可直接求出结果
P(AllTeam >= 1 && MaxTeam >= N)
= 1 - P(HasTeam < 1 || AllTeam < N)
= 1 - (P(HasTeam < 1) + P(1 < AllTeam < N))
= 1 - ((1 - P(NoTeam < 1)) + P(1 < AllTeam < N))
= P(NoTeam < 1) - P(1 < AllTeam < N)

给的时间范围时2000ms 本想开个输入外挂强行装一发。。结果写的太搓没过TOT 哪位大牛帮忙瞅瞅~

代码如下:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

double pm[1111][33],dp[33];

double read()
{
    double x = 0,p = 0.1;
    char ch = ' ';
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9') x = x*10+ch-'0',ch = getchar();
    if(ch != '.') return x;
    ch = getchar();
    while(ch >= '0' && ch <= '9') x += (ch-'0')*p,p*=0.1,ch = getchar();
    return x;
}

int main()
{
    int i,j,k,m,n,t;
    double p,sd,zer;
    while(~scanf("%d %d %d",&m,&t,&n) && m)
    {
        p = zer = 1;
        for(i = 0; i < t; ++i)
        {
            for(j = 0; j < m; ++j) scanf("%lf",&pm[i][j]);//pm[i][j] = read();
        }

        for(i = 0; i < t; ++i)
        {
            memset(dp,0,sizeof(dp));
            sd = 0;
            dp[0] = 1;
            for(j = 0; j < m; ++j)
            {
                for(k = min(j+1,n+1); k >= 0; --k)
                {
                    if(!k) dp[k] *= (1-pm[i][j]);
                    else dp[k] = (1-pm[i][j])*dp[k]+dp[k-1]*pm[i][j];
                }
            }
            for(j = 1; j < n; ++j) sd += dp[j];
            p *= sd;
            zer *= 1-dp[0];
        }
        printf("%.3lf\n",zer-p);
    }
    return 0;
}

你可能感兴趣的:(概率DP)