poj 2151 概率dp
2015-07-29 13:55
183 查看
举办一场ACM比赛很麻烦,准备的问题不能太难(爆零会让参赛者很难受),又不能没区分度(过题数一样的队伍排名从金到铁不太好吧)。所以举办方想知道所有的队伍都至少过了1题
并且冠军至少过了一定数量的题的概率。
给出比赛总题数 M 和参赛队伍数 T 和举办方希望冠军队伍至少过题数 N。
再给出每个队伍对于每道题目通过的概率p[T][M]。
求解该概率P。
对于题目要求的概率,我们可以根据容斥原理。先求出所有队伍都过一踢以上的概率P1,然后再求出所有队伍只过了(1~n-1)的·概率P2。
根据容斥原理 P = P1 - P2。
要求P1,P2 我们先要求出每个队伍过一定数量的题目的概率。
dp[i][j]表示该队伍在前i题过了j题的概率。
我们可以很容易看出:(其中p[j] 是该队伍过 j 题的概率)
dp[i][j] = dp[i-1][j] * (1 - p[j]) + dp[i-1][j-1] * p[j];
这里我们可以进行一些空间优化:(注意循环要倒着写)
dp[j] = dp[j] * (1 - p[j]) + dp[j-1] * p[j];
这样对每个队伍都进行一遍求解,我们可以得到每个队伍过指定数量题目的概率。
dp[i][j] 表示第 i 个队伍过 j 道题目的概率。
P1 = ∏(1 - dp[i][0]); (1 <= i <= T)
P2 = ∏(Σ(dp[i][j])); (1 <= i <= T , 1 <= j < N)
于是得到答案 P = P1 - P2;
并且冠军至少过了一定数量的题的概率。
给出比赛总题数 M 和参赛队伍数 T 和举办方希望冠军队伍至少过题数 N。
再给出每个队伍对于每道题目通过的概率p[T][M]。
求解该概率P。
对于题目要求的概率,我们可以根据容斥原理。先求出所有队伍都过一踢以上的概率P1,然后再求出所有队伍只过了(1~n-1)的·概率P2。
根据容斥原理 P = P1 - P2。
要求P1,P2 我们先要求出每个队伍过一定数量的题目的概率。
dp[i][j]表示该队伍在前i题过了j题的概率。
我们可以很容易看出:(其中p[j] 是该队伍过 j 题的概率)
dp[i][j] = dp[i-1][j] * (1 - p[j]) + dp[i-1][j-1] * p[j];
这里我们可以进行一些空间优化:(注意循环要倒着写)
dp[j] = dp[j] * (1 - p[j]) + dp[j-1] * p[j];
这样对每个队伍都进行一遍求解,我们可以得到每个队伍过指定数量题目的概率。
dp[i][j] 表示第 i 个队伍过 j 道题目的概率。
P1 = ∏(1 - dp[i][0]); (1 <= i <= T)
P2 = ∏(Σ(dp[i][j])); (1 <= i <= T , 1 <= j < N)
于是得到答案 P = P1 - P2;
/*********************************************** ** problem ID : poj_2151.cpp ** create time : Mon Jul 27 16:56:56 2015 ** auther name : xuelanghu ** auther blog : blog.csdn.net/xuelanghu407 **********************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int M, T, N; double p[1010][33]; double dp[1010][33]; int main () { while (cin >> M >> T >> N) { if (M == 0 && T == 0 && N == 0) break; for (int i=1; i<=T; i++) { for (int j=1; j<=M; j++) { scanf ("%lf", &p[i][j]); } } memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for (int i=1; i<=T; i++) { dp[i][0] = 1.0; for (int j=1; j<=M; j++) { for (int k=j; k>=1; k--) { dp[i][k] = dp[i][k] * (1.0 - p[i][j]) + dp[i][k-1] * p[i][j]; } dp[i][0] = dp[i][0] * (1.0 - p[i][j]); } } double res = 1.0; double rec = 1.0; for (int i=1; i<=T; i++) { res *= (1 - dp[i][0]); double tmp = 0.0; for (int j=1; j<N; j++) { tmp += dp[i][j]; } rec *= tmp; } printf("%.3lf\n", res - rec); } return 0; }
相关文章推荐
- 新手小问题总结
- Power Network 分类: POJ 2015-07-29 13:55 3人阅读 评论(0) 收藏
- IOS GCD queue group
- 黑马程序员--反射Reflect
- Android学习资料及工具网站
- HDU 1856--More is better【并查集】
- php中 $$str 中 "$$" 的解释
- Android代码内存优化建议 OnTrimMemory
- 支付宝“借条”业务悄然布局P2P,阿里能成为民间借贷的监管方吗?
- ecshop session表已经满的解决方法 The table '_sessi**' is full
- java读取配置文件
- 微博feed系统的推(push)模式和拉(pull)模式和时间分区拉模式架构探讨
- hdu 1385 Minimum Transport Cost(最短路 + 字典序最小路径)
- ios 图片处理( 1.按比例缩放 2.指定宽度按比例缩放
- 数据连接池的工作机制
- 优化MySQL,还是使用缓存?
- 目录权限设置 setfacl
- hibernate持久化对象状态
- 五款常用mysql slow log分析工具的比较分析
- linux内核中GPIO的使用(一)--IO内存