poj2151 Check the difficulty of problems(概率dp)

//题意:给你一个M,T,N, 分别代表题的总数,几只队伍,做题最多的队伍最少要做的题数量可以大于N(当然不止一个队伍),题目要求输出,所有队伍至少作对一道且有队伍至少作对N道的概率。样例中的弟i行代表弟i只队伍分别做M个题作对的概率

//思路:分析一下,设至少作对一道的概率为p已知,那么此题实际就是求作对N道的概率。然而对于作对N道题直接求该怎么求呢?首先对于每只队伍做每道题作对的概率我们已知,那么首先我们求出p。对于每个队伍如果一道题都做不出来的概率很好求设为p1,那么p = 1-p1,所有的p相乘就是所有的 队伍至少做出一道的概率p;为了求p这里我们设p[i][j]表示弟i只队伍做弟j道题的概率。用dp的思想我们设f[i][j][k]表示第i只队伍做前j道题对k道题的概率那么所有的f[i][m][0]相乘就是p1.但是如果这么做有个难点是至少做N道不好求,我们不妨在设一个变量数组s[i][j]表示第i只队伍最多作对j道题的概率,那么p就相当与所有的1-s[i][0]想乘。而此时对于至少作对N道题可以转化为:设q为最多做对n-1道,那么此题实际求的概率就是p-q。

【注意】:这里用double提交过不去,我下去仔细查了一下double与float的区别、精度以及范围,没想懂为什么。

//7324K	79MS
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxt=1010,maxm=40;
float f[maxt][maxm][maxm],s[maxt][maxm],p[maxt][maxm];


int main()
{
    int m, t, n;
    while(scanf("%d%d%d", &m, &t, &n) != EOF && m && n && t){

        for(int i = 1; i <= t; i++){
            for(int j = 1; j <= m; j++){
                scanf("%f", &p[i][j]);
            }
        }

        memset(f, 0, sizeof(f));
        for(int i = 1; i <= t; i++){
            f[i][0][0] = 1;
            for(int j = 1; j <= m; j++){
                for(int k = 0; k <= j; k++){
                    f[i][j][k] = f[i][j-1][k] * (1 - p[i][j]);
                    if(k)
                        f[i][j][k] += f[i][j-1][k-1] * p[i][j];
                }
            }
            s[i][0] = f[i][m][0];
            for(int j = 1; j <= m; j++){
                s[i][j] = s[i][j-1] + f[i][m][j];
            }
        }

        float p1 = 1, p2 = 1;
        for(int i = 1; i <= t; i++){
            p1 *= (1 - s[i][0]);
            p2 *= (s[i][n-1] - s[i][0]);
        }
        printf("%.3f\n", p1-p2);

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值