【总览】

【期望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需要顺序求解。

  概率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】的更多相关文章

  1. 【BZOJ-1419】Red is good 概率期望DP

    1419: Red is good Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 660  Solved: 257[Submit][Status][Di ...

  2. [NOIP2016]换教室 D1 T3 Floyed+期望DP

    [NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...

  3. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

  4. 【BZOJ-4008】亚瑟王 概率与期望 + DP

    4008: [HNOI2015]亚瑟王 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 832  Solved: 5 ...

  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]= ...

  6. HDU 4405 期望DP

    期望DP算是第一题吧...虽然巨水但把思路理理清楚总是好的.. 题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点.求走到n ...

  7. POJ 2096 【期望DP】

    题意: 有n种选择,每种选择对应m种状态.每种选择发生的概率相等,每种选择中对应的每种状态发生的概率相等. 求n种选择和m种状态中每种至少发生一次的期望. 期望DP好别扭啊.要用倒推的方法. dp[i ...

  8. ZOJ 3822 Domination 期望dp

    Domination Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem ...

  9. poj 2096 Collecting Bugs(期望 dp 概率 推导 分类讨论)

    Description Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other ...

  10. uva11600 状压期望dp

    一般的期望dp是, dp[i] = dp[j] * p[j] + 1; 即走到下一步需要1的时间,然后加上 下一步走到目标的期望*这一步走到下一步的概率 这一题,我们将联通分块缩为一个点,因为联通块都 ...

随机推荐

  1. GPUImage的filter 响应处理链 的理解笔记

    GPUImage的filter的textures处理链式结构 两个最重要的的地方: 最重要的一个类GPUImageOutput(所有的filter的父类,其他也有继承它的,如GPUImageUIEle ...

  2. 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大

    讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1.功能太少:2.效率低下:3.线程锁bug等等等各种莫名其妙的bug一直都没解决. 其实最重要的是log4j的作者自己也放弃了l ...

  3. 排序算法 - 选择排序(selection sort)

    选择排序(Selection sort)跟插入排序一样,也是O(n^2)的复杂度,这个排序方式也可以用我们的扑克牌来解释. 概念 桌面上有一堆牌,也是杂乱无章的,现在我们想将牌由小到大排序,如果使用选 ...

  4. bootstrap中的下拉菜单

    下拉菜单必要的代码: <div  class="container"> <div  class="dropdown"> <butt ...

  5. JAVAEE学习——struts2_03:OGNL表达式、OGNL与Struts2的结合和练习:客户列表

    一.OGNL表达式 1.简介 OGNL:对象视图导航语言.  ${user.addr.name} 这种写法就叫对象视图导航. OGNL不仅仅可以视图导航.支持比EL表达式更加丰富的功能. 2.使用OG ...

  6. MongoDB--数据库与Collection注意事项

    <h2>    <strong>注意事项:</strong></h2>1.数据库名注意应该全部小写,不能包含空格,最大长度为64K名称<br /& ...

  7. laravel中token的使用方式

    在form表单里提交表单时,可 <form action="" method="post"> <?php  echo csrf_field() ...

  8. 一张图搞定Java设计模式——工厂模式! 就问你要不要学!

    小编今天分享的内容是Java设计模式之工厂模式. 收藏之前,务必点个赞,这对小编能否在头条继续给大家分享Java的知识很重要,谢谢!文末有投票,你想了解Java的哪一部分内容,请反馈给我. 获取学习资 ...

  9. VBS自动按键大全,vbs基本和特殊按键

    CreateObject("Wscript.Shell") SendKeys [String] 脚本实现自动按键盘的某个键 过程是:按下F5间隔50毫秒松开F5间隔3000毫秒按下 ...

  10. 【TCP/IP详解 卷1:协议】 第18章TCP连接的建立与终止

    img { border: 1px solid black } T C P是一个面向连接的协议.无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接. RST:复位连接,将连接重置,一般用在 ...