概率dp作业
概率dp特征: 概率DP一般求的是实际结果,在DP过程中,当前状态是由所有子状态的概率共同转移而来,所以概率DP只是利用了DP的动态而没有规划(即只需转移无需决策)。-------qkoqhh
A - Collecting Bugs
题意:一个软件有s个子系统,会产生n种bug。某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s,属于某种类型的概率是1/n。
这题放在第一个,自然是入门题目,这里我在仔细温习下聚聚讲的状态和转移:
f[i][j]:表示已经找到i种bug,分j类,找完剩下bug需要天数的期望。
转移分4中情况,即分类和系统对于已知和未知的4种组合。
相应概率也可以得出。注意4种状态对应的概率求和为1
边界:f[n][s]= 求f[][]
方程:dp[i][j]=(n-i)/n*(s-j)/s*dp[i+][j+]+(n-i)/n*j/s*dp[i+][j]+i/n*(s-j)/s*dp[i][j+]+i/n*j/s*dp[i][j]+
这里方程后面加1因为这是计算下一状态的期望,所以+1。
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = ;
double dp[maxn][maxn];
int main()
{
//freopen("in.txt", "r", stdin);
int n, s;
while(scanf("%d%d", &n, &s) != EOF){
dp[n][s] = ;
for(int i=n; i>=; i--){
for(int j=s; j>=; j--){
if(i==n && j==s)continue;
dp[i][j] = (dp[i+][j]*(n-i)*j+dp[i][j+]*i*(s-j)+dp[i+][j+]*(n-i)*(s-j)+n*s)/(n*s-i*j);
}
}
printf("%.4f\n", dp[][]);
}
return ;
}
B - Card Collector
题意:
集齐n张不同概率(p1,p2……pn)的卡片(一包最多一张)需要买多少包小吃,求期望。
Thinkging:
看数据范围n<=20,可以思考状态压缩(qkoqhh说的)。
这题状态也比较好定义 dp[s]: 已经收集到一些卡牌,状态压缩为s,要收集到所有卡牌的期望。
这题方程也比较好写
dp[s] = Σ dp[s]*(q1+q2) (s>>j & )== //q1:没有卡片的概率 q2:抽出集合中存在的卡片
+ Σ dp[s | <<j] * p[j] (s>>j & )==
#include <cstdio>
#include <cstring>
const int maxn = ;
double P[maxn];
double dp[<<maxn];
int main(){
// freopen("in.txt", "r", stdin);
int n;
while(scanf("%d", &n) != EOF){
double p = ;
for(int i=; i<n; i++){
scanf("%lf", &P[i]);
p += P[i];
}
p = - p; //袋里没有卡片的概率
dp[(<<n)-] = ;
for(int s=(<<n)-; s>=; s--){
double x = , y = ;
for(int j=; j<n; j++){
if((s>>j) & ){
x += P[j];
}else{
y += P[j]*dp[s | (<<j)];
}
dp[s] = y/(-x-p);
}
}
printf("%.5f\n", dp[]);
}
return ;
}
C - Aeroplane chess
题意:在一个从0到n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点。求走到n或超出n期望掷色子次数。
Thinking:
如果只是摇色子不飞行的话有如下转移:
dp[i]:从i走到n的期望步数
dp[i]= Σ /*dp[i+k]+1 k=..
加入飞行方式后两点的期望步数相等
这里可以用并查集维护飞行点的dp转移,注意并查集根部维护的是目标方向的结点
也可以用链式存储转移的关系,同样反向建立链接关系。
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = ;
double dp[maxn];
int f[maxn];
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
int main(){
// freopen("in.txt", "r", stdin);
int n, m;
while( scanf("%d%d", &n, &m) != EOF && n){
memset(dp, , sizeof(dp));
memset(f, , sizeof(f));
for(int i=; i<=n+; i++){
f[i] = i;
}
for(int i=; i<m; i++){
int x, y;
scanf("%d%d", &x,&y);
f[find(x)] = find(y);
}
for(int i=n-; i>=; i--){
if(find(i) == i){ //这是不能跳跃的点
for(int j=i+; j<=i+; j++){
dp[i] += (dp[find(j)] + )/;
}
}
}
printf("%.4f\n", dp[]);
}
}
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = ;
double dp[maxn];
bool vis[maxn];
vector<int> G[maxn];
int main(){
// freopen("in.txt", "r", stdin);
int n, m;
while( scanf("%d%d", &n, &m) != EOF && (n+m)){
memset(dp, , sizeof(dp));
memset(vis, , sizeof(vis));
for(int i=; i<=n; i++)G[i].clear();
for(int i=; i<m; i++){
int x, y;
scanf("%d%d", &x,&y);
G[y].push_back(x);
/*
*反向建立链表,存储直接跳转的点对,方便下面逆着转移
*/
}
for(int i=; i<G[n].size(); i++){
vis[G[n][i]] = true;
}//与终点相连的点可直接跳转
for(int i=n-; i>=; i--){
if(!vis[i]){ //这是不能跳跃的点
for(int j=i+; j<=i+; j++){
dp[i] += dp[j]/;
}
dp[i] += ;
vis[i] = true;
}
for(int j=; j<G[i].size(); j++){
dp[G[i][j]] = dp[i];
vis[G[i][j]] = true;
}//可以直接跳转的点
}
printf("%.4f\n", dp[]);
}
return ;
}
E - Bag of mice
题意:一个袋子里有n个白老鼠,m个黑老鼠,王子和龙依次取,王子先取,先取到白老鼠的为胜者,其中龙取老鼠的时候,取出一只后,会有随机的一只老鼠跑出来,而且取老鼠的时候,每只老鼠取到的概率是一样的,跑出来的概率也是一样的,算王子赢的概率。
这里学习了kuangbin对这题的解析。看tutorial里用将问题分解为两个子问题(W,B)->(W,B-1)+(W-1,B-1)+(W,B-2),这里可以设置一个标记回合的参数。
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long const int maxn = ;
double dp[maxn][maxn];
//dp[i][j]:到王妃抓时还剩 i只白鼠j只黑鼠时王妃胜的概率
int main(){
//freopen("in.txt", "r", stdin);
memset(dp, , sizeof());
int w,b;
scanf("%d%d", &w, &b);
for(int i=; i<=b; i++)dp[][i]=;
// 没有白鼠时胜率为0
for(int i=; i<=w; i++)dp[i][]=;
//没有黑鼠时 胜率为1
for(int i=; i<=w; i++){
for(int j=; j<=b; j++){
dp[i][j] += (double)i/(i+j);//王妃抓到一只白鼠
if(j>=){
dp[i][j] += ((double)j/(i+j)) * ((double)(j-)/(i+j-)) * ((double)(j-)/(i+j-)) * dp[i][j-];
}//王妃抓到黑,龙抓到一个黑,放了一个黑
if(j>=){
dp[i][j] += ((double)j/(i+j)) * ((double)(j-)/(i+j-)) * ((double)i/(i+j-)) * dp[i-][j-];
}//王妃抓到黑,龙抓到黑,放了一个白
}
}
printf("%.9lf\n", dp[w][b]);
return ;
}
double dfs(int w, int b, int flag){
if(w == ) return flag; //flag=1:此轮龙抓,龙胜返回1; 代表两人都没抓到白鼠,龙胜
if(b == ) return ;
double &memo = dp[w][b][flag];
if(memo > -0.5) return memo;
double ans = ;
if(flag == ){
ans += (double)w/(w + b); //王妃抓白鼠胜
ans += ((double)b/(w + b)) * ( - dfs(w, b-, ));
//王妃抓黑鼠,下一轮龙抓失败的概率(dfs()返回成功的概率) 即王妃胜
}else{
ans += (double)w/(w + b); //龙抓白鼠胜的概率
ans += ((double)b/(w + b)) * ((double)w/(w+b-)) * ( - dfs(w-, b-, ));
// 龙抓一个黑鼠放一个白鼠胜的概率
if(b > ) { //龙抓一个黑鼠 放一个黑鼠胜的概率
ans += ((double)b/(w + b)) * ((double)(b-)/(w + b-)) * ( - dfs(w, b-, ));
}
}
return memo = ans;
}
dp[i][j][]=dp[i][j][] = -
概率dp作业的更多相关文章
- [TS-A1489][2013中国国家集训队第二次作业]抽奖[概率dp]
概率dp第一题,开始根本没搞懂,后来看了09年汤可因论文才基本搞懂,关键就是递推的时候做差比较一下,考虑新加入的情况对期望值的贡献,然后推推公式(好像还是不太会推qaq...) #include &l ...
- Codeforces 28C [概率DP]
/* 大连热身D题 题意: 有n个人,m个浴室每个浴室有ai个喷头,每个人等概率得选择一个浴室. 每个浴室的人都在喷头前边排队,而且每个浴室内保证大家都尽可能均匀得在喷头后边排队. 求所有浴室中最长队 ...
- HDU 4405 Aeroplane chess (概率DP)
题意:你从0开始,要跳到 n 这个位置,如果当前位置是一个飞行点,那么可以跳过去,要不然就只能掷骰子,问你要掷的次数数学期望,到达或者超过n. 析:概率DP,dp[i] 表示从 i 这个位置到达 n ...
- POJ 2096 Collecting Bugs (概率DP)
题意:给定 n 类bug,和 s 个子系统,每天可以找出一个bug,求找出 n 类型的bug,并且 s 个都至少有一个的期望是多少. 析:应该是一个很简单的概率DP,dp[i][j] 表示已经从 j ...
- POJ 2151 Check the difficulty of problems (概率DP)
题意:ACM比赛中,共M道题,T个队,pij表示第i队解出第j题的概率 ,求每队至少解出一题且冠军队至少解出N道题的概率. 析:概率DP,dp[i][j][k] 表示第 i 个队伍,前 j 个题,解出 ...
- 概率DP light oj 1030
t组数据 n块黄金 到这里就捡起来 出发点1 到n结束 点+位置>n 重掷一次 dp[i] 代表到这里的概率 dp[i]=(dp[i-1]+dp[i-2]... )/6 如果满6个的话 否则 ...
- hdu 4050 2011北京赛区网络赛K 概率dp ***
题目:给出1-n连续的方格,从0开始,每一个格子有4个状态,左右脚交替,向右跳,而且每一步的步长必须在给定的区间之内.当跳出n个格子或者没有格子可以跳的时候就结束了,求出游戏的期望步数 0:表示不能到 ...
- [转]概率DP总结 by kuangbin
概率类题目一直比较弱,准备把kuangbin大师傅总结的这篇题刷一下! 我把下面的代码换成了自己的代码! 原文地址:http://www.cnblogs.com/kuangbin/archive/20 ...
- SGU 422 Fast Typing(概率DP)
题目大意 某人在打字机上打一个字符串,给出了他打每个字符出错的概率 q[i]. 打一个字符需要单位1的时间,删除一个字符也需要单位1的时间.在任意时刻,他可以花 t 的时间检查整个打出来的字符串,并且 ...
随机推荐
- BIgDecimal输出时添加金额分割符
1.创建Serializer文件 2.修改输出方法 3.使用
- Linux学习日志(一)
1 .Ubuntu 自带python 2 和 python 3的版本,切换方法如下: shell里执行: sudo update-alternatives --install /usr/bin/pyt ...
- java双指针的简单理解
一.什么是双指针 双指针我所理解地是在遍历对象时,不是使用单个指针进行访问,而是使用两个相同方向或者相反方向的指针进行遍历,从而达到相应的目的. 在JAVA中并没有像C/C++指针地概念,所以这里所说 ...
- Bootstrap-轮播图-No.9
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- .net core 自动注入。。。。懵逼。。
using Microsoft.AspNetCore.Http; using System.Globalization; using System.Threading.Tasks; namespace ...
- SQL Server孤立用戶
如何解决孤立用户问题 http://blog.csdn.net/zzl1120/article/details/7394468 SQL SERVER孤立用户问题解决方法 http://www.2cto ...
- luogu 1220 关路灯 区间dp
Code: #include <bits/stdc++.h> #define ll long long #define N 1003 #define setIO(s) freopen(s& ...
- [Luogu] 小凯的疑惑
https://www.luogu.org/problemnew/show/P3951 考场上打表找规律的我写出了这样一份代码(紧张到爆<已经爆>) 当时一出考场听说是O(1)做法,当时就 ...
- 【csp模拟赛2】 爆搜 方格加数
[题目描述] xyz1048576正在玩一个关于矩阵的游戏. 一个n*m的矩阵,矩阵中每个数都是[1,12]内的整数.你可以执行下列两个操作任意多次: (1)指定一行,将该行所有数字+1. (2)指定 ...
- 【CUDA 基础】5.2 共享内存的数据布局
title: [CUDA 基础]5.2 共享内存的数据布局 categories: - CUDA - Freshman tags: - 行主序 - 列主序 toc: true date: 2018-0 ...