【期望DP】
【总览】
【期望dp】
求解达到某一目标的期望花费:因为最终的花费无从知晓(不可能从$\infty$推起),所以期望dp需要倒序求解。
设$f[i][j]$表示在$(i, j)$这个状态实现目标的期望值(相当于是差距是多少)。
首先$f[n][m] = 0$,在目标状态期望值为0。然后$f = (\sum f' × p) + w $,$f'$为上一状态(距离目标更近的那个,倒序),$p$为从$f$转移到$f'$的概率(则从$f'$转移回$f$的概率也为$p$),w为转移的花费。
最后输出初始位置的$f$即可。
特别的,当转移关系不成环时,期望dp可以线性递推。
但当转移关系成环时,期望dp的最终状态相当于一个已知量,而转移关系相当于一个个方程,可以使用【高斯消元】解决。
【概率dp】
概率dp通常已知初始的状态, 然后求解最终达到目标的概率,所以概率dp需要顺序求解。
概率dp相对简单,当前状态只需加上所有上一状态乘上转移概率即可:$f = \sum f'_{i} × p_{i}$
【例题】
【hdu3853】Loops
简单的期望dp题,设$f[i][j]$表示当前位置到达终点的期望体力,则$f[r][c] = 0$。
已知每个位置不动、向下、向右的概率。设p0为当前状态下停留的概率,p1为向下的概率,p2为向右的概率,那么就从终点开始逆推:
$$f[i][j] = p0 × f[i][j] + p1 × f[i + 1][j] + p2 × f[i][j +1] + 2$$
dp强调根据已知推未知,发现等号右边$f[i][j]$正是我们要求的,呢么这就可以构成一个方程了。不过没有那么复杂,因为转移关系不是一个环,只要我们将右边的$f[i][j]$移到左边,再将系数除过去,等号右边就都是已知的了。
【CODE】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std; const int R = , C = ;
const double eps = 1e-;
int r, c;
double p[R][C][];
double f[R][C]; int main(){
while(scanf("%d%d", &r, &c) != EOF){
memset(p, , sizeof p);
memset(f, , sizeof f);
for(int i = ; i <= r; i++)
for(int j = ; j <= c; j++)
scanf("%lf%lf%lf", &p[i][j][], &p[i][j][], &p[i][j][]);
f[r][c] = ;
for(int i = r; i >= ; i--)
for(int j = c; j >= ; j--){
if(i == r && j == c) continue;
if(fabs(1.0 - p[i][j][]) < eps) continue;
f[i][j] = (p[i][j][] * f[i][j + ] + p[i][j][] * f[i + ][j] + 2.0) / (1.0 - p[i][j][]);
}
printf("%.3f\n", f[][]);
}
return ;
}
【hdu4405】AeroplaneChess
又是一道期望dp。读题可知终点落在$n$~ $n + 5$,将它们的f全部置为$0$。
因为有直接跳转,所以如果当前点有可以直接跳转到的点,那么这次是不用掷骰子的,因为当前期望等于目标点的期望。
然后考虑掷色子,摇到$1, 2, 3, 4, , 6$的概率都为$\frac{1}{6}$,所以$f[i] = \sum_{x = 1}^{6} f[i + x] × \frac{1}{6} + 1$
这样倒序dp便可以得到期望值。
【CODE】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std; const int N = ;
int go[N];
int n, m;
double f[N]; int main(){
while(~scanf("%d%d", &n, &m), n + m){
memset(go, -, sizeof go);
for(int i = ; i <= m; i++){
int x, y; scanf("%d%d", &x, &y);
go[x] = y;
}
memset(f, , sizeof f);
for(int i = n - ; i >= ; i--){
if(go[i] != -){
f[i] = f[go[i]];
continue;
}
f[i] = (f[i + ] + f[i + ] + f[i + ] + f[i + ] + f[i + ] + f[i + ]) / + ;
}
printf("%.4f\n", f[]);
}
return ;
}
【poj2096】收集错误
这道题很有意思。设$f[i][j]$为收集到$i$种bug,属于$j$个子系统的期望天数,同样$f[n][s] = 0$
考虑当前bug:
- 属于已经收集到的$i$种,也属于已经收集到的$j$个系统,概率为$\frac{i × j}{n × s}$
- 属于已经收集到的$i$种,属于新的一套系统, 概率为$\frac{i × (s - j)}{n × s}$
- 属于新的一种,属于已经收集到的$j$个系统,概率为$\frac{(n - i) × j}{n × s}$
- 属于新的一种,属于新的系统,概率为$\frac{(n - i) × (s - j)}{n × s}$
上面顺推求出的概率,应该是等于逆推的概率的。
其余的就很基础了。
【CODE】
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std; const int N = , S = ;
double f[N][S];
int n, s; int main(){
scanf("%d%d", &n, &s);
f[n][s] = 0.0;
for(int i = n; i >= ; i--){
for(int j = s; j >= ; j--){
if(n * s - i * j == ) continue;
double c1 = (double)i * ((double)s - (double)j), c2 = ((double)n - (double)i) * (double)j,
c3 = ((double)n - (double)i) * ((double)s - (double)j), c4 = (double)n * (double)s, c5 = (double)n * (double)s - (double)i * (double)j;
f[i][j] = ((c1 * f[i][j + ] + c2 * f[i + ][j] + c3 * f[i + ][j + ] + c4) / c5);
}
}
printf("%.4f\n", f[][]);
return ;
}
【poj3071】FootBall
终于到概率dp了。设$f[i][j]$表示当前第$i$轮比赛,$j$队获胜的概率,那么他如果想获胜:
- 首先上一轮比赛他必须获胜。
- 然后他的对手上一轮必须获胜。
- 他的对手只能是相邻的。
判断相邻十分巧妙的使用了二进制:如果把所有队伍的编号都$-1$:
从$0$开始的自然数(二进制):$0, 1, 10, 11, 100, 101, ......$
可以发现相邻的数它们的最后一位一定相反。
进行第一轮比赛后,相当于将相邻俩个节点替换成他们的父节点$(k >> 1)即将最后一位去掉$,此时相邻的点仍然符合规律。
所以我们判断两队是否能比赛的标准就是:$(j >> (i - 1)) $ ^ $1 == k >> (i - 1)$
【CODE】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std; const int N = ;
int n;
double f[N][], p[][]; int main(){
freopen("h.in", "r", stdin);
while(scanf("%d", &n), n != -){ memset(p, , sizeof p);
memset(f, , sizeof f);
for(int i = ; i <= ( << n); i++){
f[][i] = ;
for(int j = ; j <= ( << n) ; j++)
scanf("%lf", &p[i][j]);
}
for(int i = ; i <= n; i++)
for(int j = ; j <= ( << n); j++)
for(int k = ; k <= ( << n); k++)
if((((j - ) >> (i - )) ^ ) == ((k - ) >> (i - )))
f[i][j] += f[i - ][k] * f[i - ][j] * p[j][k];
double ans = -;
int ret = ;
for(int i = ; i <= ( << n); i++)
if(ans < f[n][i]) ans = max(ans, f[n][i]), ret = i;
printf("%d\n", ret);
}
}
【期望DP】的更多相关文章
- 【BZOJ-1419】Red is good 概率期望DP
1419: Red is good Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 660 Solved: 257[Submit][Status][Di ...
- [NOIP2016]换教室 D1 T3 Floyed+期望DP
[NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...
- HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)
题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...
- 【BZOJ-4008】亚瑟王 概率与期望 + DP
4008: [HNOI2015]亚瑟王 Time Limit: 20 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 832 Solved: 5 ...
- 期望dp BZOJ3450+BZOJ4318
BZOJ3450 概率期望DP f[i]表示到i的期望得分,g[i]表示到i的期望长度. 分三种情况转移: ① s[i]=‘x’:f[i]=f[i-1],g[i]=0 ② s[i]=‘o’:f[i]= ...
- HDU 4405 期望DP
期望DP算是第一题吧...虽然巨水但把思路理理清楚总是好的.. 题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点.求走到n ...
- POJ 2096 【期望DP】
题意: 有n种选择,每种选择对应m种状态.每种选择发生的概率相等,每种选择中对应的每种状态发生的概率相等. 求n种选择和m种状态中每种至少发生一次的期望. 期望DP好别扭啊.要用倒推的方法. dp[i ...
- ZOJ 3822 Domination 期望dp
Domination Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem ...
- poj 2096 Collecting Bugs(期望 dp 概率 推导 分类讨论)
Description Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other ...
- uva11600 状压期望dp
一般的期望dp是, dp[i] = dp[j] * p[j] + 1; 即走到下一步需要1的时间,然后加上 下一步走到目标的期望*这一步走到下一步的概率 这一题,我们将联通分块缩为一个点,因为联通块都 ...
随机推荐
- GPUImage的filter 响应处理链 的理解笔记
GPUImage的filter的textures处理链式结构 两个最重要的的地方: 最重要的一个类GPUImageOutput(所有的filter的父类,其他也有继承它的,如GPUImageUIEle ...
- 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大
讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1.功能太少:2.效率低下:3.线程锁bug等等等各种莫名其妙的bug一直都没解决. 其实最重要的是log4j的作者自己也放弃了l ...
- 排序算法 - 选择排序(selection sort)
选择排序(Selection sort)跟插入排序一样,也是O(n^2)的复杂度,这个排序方式也可以用我们的扑克牌来解释. 概念 桌面上有一堆牌,也是杂乱无章的,现在我们想将牌由小到大排序,如果使用选 ...
- bootstrap中的下拉菜单
下拉菜单必要的代码: <div class="container"> <div class="dropdown"> <butt ...
- JAVAEE学习——struts2_03:OGNL表达式、OGNL与Struts2的结合和练习:客户列表
一.OGNL表达式 1.简介 OGNL:对象视图导航语言. ${user.addr.name} 这种写法就叫对象视图导航. OGNL不仅仅可以视图导航.支持比EL表达式更加丰富的功能. 2.使用OG ...
- MongoDB--数据库与Collection注意事项
<h2> <strong>注意事项:</strong></h2>1.数据库名注意应该全部小写,不能包含空格,最大长度为64K名称<br /& ...
- laravel中token的使用方式
在form表单里提交表单时,可 <form action="" method="post"> <?php echo csrf_field() ...
- 一张图搞定Java设计模式——工厂模式! 就问你要不要学!
小编今天分享的内容是Java设计模式之工厂模式. 收藏之前,务必点个赞,这对小编能否在头条继续给大家分享Java的知识很重要,谢谢!文末有投票,你想了解Java的哪一部分内容,请反馈给我. 获取学习资 ...
- VBS自动按键大全,vbs基本和特殊按键
CreateObject("Wscript.Shell") SendKeys [String] 脚本实现自动按键盘的某个键 过程是:按下F5间隔50毫秒松开F5间隔3000毫秒按下 ...
- 【TCP/IP详解 卷1:协议】 第18章TCP连接的建立与终止
img { border: 1px solid black } T C P是一个面向连接的协议.无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接. RST:复位连接,将连接重置,一般用在 ...