poj-2151

#include <stdio.h>
#include <string.h>

double DP[50][50];

double P[1010];
double PSolveN[1010][50];
double PSolveNAcc[1010][50];

void getMENP(double * array, int N, int length, int M, double (* PSolveN)[50] ) // MENP: more/equal N questions probability
{
    // printf("N %d length %d M %d\n", N, length, M);
    // if (N > length) {
    //     return 0;
    // }
    memset(DP, 0, sizeof(DP));
    


    int i = 0;
    for (; i <= length; i++) {
        int j = 0;
        for (; j<=M; j++) {
            if (i < j) { // imposible
                DP[i][j] = 0;
            } else if (i == 0 && j == 0) { // must be
                DP[i][j] = 1;
            } else if (j == 0) {
                DP[i][j] = (1-array[i-1]) * DP[i-1][j];
            } else {
                double p1 = DP[i-1][j];
                double p2 = DP[i-1][j-1];
                double solveThisP = p2*array[i-1];
                double noSolveThisP = p1*(1- array[i-1]);

                DP[i][j] = solveThisP + noSolveThisP;
                // printf("%d %d %lf\n", i, j, DP[i][j]);
            }
        }
    }
    
    for (int j = 0; j <=length; j++) {
        (*PSolveN)[j] =  DP[length][j];
    }
}

int main() {
    int M;
    int T;
    int N;
    while(1){
        memset(P, 0, sizeof(P));
        memset(PSolveN, 0, sizeof(PSolveN));
        memset(PSolveNAcc, 0, sizeof(PSolveNAcc));

        double res = 0;
        double AllME1P = 1;
        double AllLNME1 = 1;
        scanf("%d %d %d", &T, &M, &N);
        if (0 == M &&
            0 == T &&
            0 == N) {
            return 0;
        }
        
        if (T < N) {
            printf("%.3f\n", 0.0);
            continue;
        }

        int i = 0;
        for (; i < M; i++) {
            int j = 0;
            for (; j < T; j++) {
                scanf("%lf", P+j);
            }
            getMENP(P, N, T, M, PSolveN + i);
        }

        for (i = 0; i< M; i++) {
            int j = 0;
            for (; j <= T; j++) {
                if (0 == j) {
                    PSolveNAcc[i][j] = PSolveN[i][j];
                } else {
                    PSolveNAcc[i][j] = PSolveN[i][j] + PSolveNAcc[i][j-1];            
                }
                // printf("%d %d %.3lf ", i ,j, PSolveNAcc[i][j]);
            }
            // printf("\n");
        }

        for (i = 0; i < M; i++) {
            AllME1P *= (1-PSolveN[i][0]);
        }
 
        for (i = 0; i < M; i++) {
            AllLNME1 *= (PSolveNAcc[i][N-1] - PSolveNAcc[i][0]);    
        }

        res = AllME1P - AllLNME1;
        // printf("%f %f\n", AllME1P, AllLNME1);

        printf("%.3f\n", res);
    }

}


G++ 1188K 79MS.

悲催一题, 因为RE卡了半天, 后来才发现,自己把 T(队伍数量 1~1000)和M(题目数量 1~ 30) 搞混了, 这样必然后面数组访问会出错,

当时发现了这个问题,输入时搞颠倒了,但是没有接着把用到的数组的尺寸调换,妈的,真是2B的超出了自己的想象, 后面为了排查RE,直接把poj当成调试器用了...

悲剧的是,最后还是靠直接看代码发现的这个问题.... 唉, 发现现在自己现在思维有问题,写完code,就懒得再仔细的检查,直接上数据,有错了再用数据debug,

诚然, 很多算法题第一遍就就写对的难度还是蛮高的,但是不能因为这个就完全指望测试,测试终究有自己的覆盖范围(poj 很多AC的最后其实还是有问题的)。

以后必须要强化审阅code,就像现在工作中一样,不能指望别人code rebview给你发现问题,一个合格的程序员,必须在自己脑子里对自己的code有最清晰和肯定的认识.

唉,其实我现在有时候就是code AC了, 还是没底,一定要消除这个问题了.


回到题本身, 这道题我在刷题指南里看到,被分到了hash,其实应该不是, 硬要归,就是概率论+DP.

DP在这里的作用就是求出了 某一队在整场比赛解出k道题的概率, 一开始还想着按照传统数学思路来,后来发现是作死,看了discuss以后一想,确实DP可以用在这里:

以前解DP题,大都是求最优解,及每个解之间是要比较的,但这只是DP的一个种类,有些DP, 不是要求最优解,而是子问题解之间的一种组合。

对某一队(解题概率数组P)来说, 定义D[i][j]为该队在前i道题中解出j道题的概率, 那么,就有:

D[i][j] = D[i-1][j]*(1- P[i])<第i题没有解出来,前i-1道题已经解出了j道 > + D[i-1][j-1]*P[i]<解出第i道题, 前i-1道题解出了j-1道>, 其实正好是一个概率组合.

对某些特殊情况:

i< j : 不可能, 0;

i== 0 && j == 0: 一定会发生,  1;

i>0 & j == 0, D[i][j] = D[i-1][j]*(1- P[i])  D[i-1][j-1] 是没有意义的情况(做出的题是-1道), 从概率论上考虑,做到第i道解出0道题的概率一定等于(1-P[i]) *<解到前i-1题,解出0道的概率>, 因为不可能解出负数的题.


这个数组求出来以后,取 i= M的情况,那么就表示的是 在比赛中,该队解出第 0, 1 ,2 ,3 ... M道题的概率 ,其实一个二维数组了,以为每一队都有一个自己的这样的数组.

那么,根据题意, 只有每一队解出了>=1道题, 且至少由一队解出了>=N道题(注意,这里是至少一队, 这就意味着有多个队解出了同样数量的>=N的题也是合理的解).

哎,这时候显出概率论的不足了, 想了很长时间都找不到一个简单的表达合理解的概率组合方式.

后来在想出来,满足解的概率应该是这样:

每一队都解出了>=1道题的概率 -  每一队都解出了>=1道的题,但是每一对只解出了<N道题.

有了之前解出的前i道题解出j道题概率数组PSolveN,进行一次处理:

用PSolveNAcc[i][j] 表示对于第i队,在比赛中 至少解出了j道题的概率(及解出了0, 1 ,2 ..j 道题的概率的总和),

那么PSolveNAcc[i][j] = PSolveN[i][j] + PSolveNAcc[i][j-1].

最后就是做个减法即可.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值