POJ 2151 概率 DP

159 篇文章 1 订阅
题意

传送门 POJ 2151

题解

设事件 A A A 为每支队伍至少通过一题,事件 B B B 为每只队伍通过题目的数量在区间 [ 1 , n − 1 ] [1,n-1] [1,n1] 内。各队伍通过的题目数的事件相互独立。
P ( A ) = ∏ 0 ≤ i < T ( 1 − ∏ 0 ≤ j < M ( 1 − p i j ) ) P(A)=\prod_{0\leq i<T}(1-\prod_{0\leq j<M}(1-p_{ij})) P(A)=0i<T(10j<M(1pij))
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 代表队伍 i i i [ 0 , j ] [0,j] [0,j] 题内通过了 k k k 题的概率。对于题目 j j j,有通过与不通过两种可能,则有递推式
d p [ i ] [ j ] [ k ] = d p [ i ] [ j − 1 ] [ k ] ∗ ( 1 − p [ i ] [ j ] ) + d p [ i ] [ j − 1 ] [ k − 1 ] ∗ p [ i ] [ j ] dp[i][j][k]=dp[i][j-1][k]*(1-p[i][j])+dp[i][j-1][k-1]*p[i][j] dp[i][j][k]=dp[i][j1][k](1p[i][j])+dp[i][j1][k1]p[i][j]则有
P ( B ) = ∏ 0 ≤ i < T ( ∑ 1 ≤ k < n d p [ i ] [ M − 1 ] [ k ] ) P(B)=\prod_{0\leq i<T}(\sum_{1\leq k<n}dp[i][M-1][k]) P(B)=0i<T(1k<ndp[i][M1][k]) D P DP DP 第一维可压缩,实现上使用滚动数组。答案即 P ( A ) − P ( B ) P(A)-P(B) P(A)P(B)

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxt 1005
#define maxm 35
int M, T, N;
double p[maxt][maxm], dp[2][maxm];

int main()
{
    while (~scanf("%d%d%d", &M, &T, &N) && (M | T | N))
    {
        for (int i = 0; i < T; i++)
        {
            for (int j = 0; j < M; j++)
            {
                scanf("%lf", &p[i][j]);
            }
        }
        // 每只队伍至少通过1题的概率, 每只队伍通过1~n-1题的概率
        double p1 = 1, p2 = 1;
        for (int i = 0; i < T; i++)
        {
            double tmp = 1;
            for (int j = 0; j < M; j++)
            {
                tmp *= 1 - p[i][j];
            }
            p1 *= 1 - tmp;
        }
        for (int i = 0; i < T; i++)
        {
            memset(dp, 0, sizeof(dp));
            double *crt = dp[0], *nxt = dp[1];
            crt[0] = 1;
            for (int j = 0; j < M; j++)
            {
                nxt[0] = crt[0] * (1 - p[i][j]);
                for (int k = 1; k <= j + 1; k++)
                {
                    nxt[k] = crt[k] * (1 - p[i][j]) + crt[k - 1] * p[i][j];
                }
                swap(crt, nxt);
            }
            double tmp = 0;
            for (int j = 1; j < N; j++)
            {
                tmp += crt[j];
            }
            p2 *= tmp;
        }
        printf("%.3lf\n", p1 - p2);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值