XDU-1043 Boooooom (概率DP)

1043: Boooooom

时间限制:  1 Sec   内存限制:  128 MB   Special Judge
http://acm.xidian.edu.cn/problem.php?id=1043
[ 提交 ][ 状态 ][ 讨论版 ]

题目描述

BoomUUZ发飙了。参加ACM的培训本应该有n个人,今天却只来了那么一点点。已知每个学生能来上课的概率为Pi(1in),当上课人数少于k时,UUZ会发飙,一旦UUZ发飙,那么以后的课(包括这节课)就都不上了,而如果不发飙,则UUZ还会开下一节课。那么,UUZ能为大家开课的期望大约是多少堂呢?精确到0.1就可以了。

输入

有多组输入数据,第一行为一个数字T,代表有T组输入数据 (0<T10)

接下来为T组数据。

每组数据的第一行为两个整数nk,其中,1n201kn.

接下来的一行有n个整数1位小数(大于0小于1),表示这n个学生来上课的概率。

输出

对于每组数据,在一行上输出一个实数,表示UUZ上课的期望值。

只要答案的相对误差在10-6以内,或绝对误差在0.1以内,都判为正确。

样例输入

1
3 1
0.1 0.1 0.1

样例输出

0.4

设dp[i][j]表示前i个人中有j个人来上课的概率,初始:dp[0][0]=0;

态转移方程为:dp[i][j]=dp[i-1][j]*(1-p[i])+dp[i-1][j-1]*p[i];

计算n个人中来上课的人数大于等于k时的概率为sum

则可求的上课天数的期望为:sum+sum^2+…+sum^x,(x→

等比数列求和得:sum/(1-sum)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,k;
double p[25];
long double dp[25][25],sum;//dp[i][j]表示前i个人中有j个人来上课的概率

int main() {
    int T;
    scanf("%d",&T);
    while(T-->0) {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i) {
            scanf("%lf",p+i);
        }
        dp[0][0]=1;
        for(int i=1;i<=n;++i) {
            for(int j=0;j<i;++j) {
                dp[i][j]=dp[i-1][j]*(1-p[i])+dp[i-1][j-1]*p[i];
            }
            dp[i][i]=dp[i-1][i-1]*p[i];
        }
        sum=0;//sum表示n个人中来上课的人数大于等于k时的概率
        for(int i=k;i<=n;++i) {
            sum+=dp[n][i];
        }
        printf("%.2lf\n",double(sum/(1-sum)));
    }
    return 0;
}


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