期望dp专题

一直不明白为什么概率是正推,期望是逆推。 现在题目做多了,慢慢好像有点明白了

poj2096

收集bug,  有n个种类的bug,和s个子系统。  每找到一个bug需要一天。

要我我们求找到n个种类的bug,且在每个系统中都找到一个bug的期望天数

设dp[i][j] 为找到i个种类的bug和在j个系统中找到bug后,还需要的期望天数

那么dp[n][s] 肯定是0,而dp[0][0]是我们要求的。 这也就是为什么期望是要逆推。

还有一点就是这一状态的期望会等于   所有(下一状态的的期望*这一状态走向下一状态的概率)的和+1

所有可能的情况如下

找到了一个新种类的bug (n-i)/n 第一维度增加1,在一个已经找到bug的系统里面j/s, 第二维度不增加
找到了一个旧种类的bug i/n 第一维度不增加,在一个没有找到bug的系统里面 (s-j)/s 第二维度增加,
找到了一个新种类的bug (n-i)/n 第一维度增加,在一个没有找到bug的系统里面 (s-j)/s 第二维度增加,
找到了一个旧种类的bug i/n 第一维度不增加 , 在一个已经找到bug的系统里面 j/s 第二维度不增加

所有状态转移方程是

dp[i][j] = (1-i/n)*j/s*dp[i+1][j] + i/n*(1-j/s)*dp[i][j+1] + (1-i/n)*(1-j/s) * dp[i+1][j+1] + i/n*j/s*dp[i][j]    + 1

将红色的部分移到左边化简后得到

dp[i][j] = ((1-i/n)*j/s*dp[i+1][j] + i/n*(1-j/s)*dp[i][j+1] + (1-i/n)*(1-j/s) * dp[i+1][j+1] +1)/(1-i/n*j/s)

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 #pragma comment(linker, "/STACK:1024000000,1024000000")
16 typedef long long LL;
17 const int INF = 1 << 30;
18 /*
19 double dp[n][s] 表示已经找到n个种类的bug,在s个子系统中都找到了bug的期望天数
20
21 找到了一个新种类的bug (n-i)/n   第一维度增加1,在一个已经找到bug的系统里面j/s,       第二维度不增加
22 找到了一个旧种类的bug  i/n      第一维度不增加,在一个没有找到bug的系统里面 (s-j)/s   第二维度增加,
23 找到了一个新种类的bug (n-i)/n   第一维度增加,在一个没有找到bug的系统里面 (s-j)/s     第二维度增加,
24 找到了一个旧种类的bug i/n       第一维度不增加 , 在一个已经找到bug的系统里面 j/s     第二维度不增加
25
26 dp[i][j] = (1-i/n)*j/s*dp[i+1][j] + i/n*(1-j/s)*dp[i][j+1] + (1-i/n)*(1-j/s) * dp[i+1][j+1] + i/n*j/s*dp[i][j]
27
28 dp[i][j] = ((1-i/n)*j/s*dp[i+1][j] + i/n*(1-j/s)*dp[i][j+1] + (1-i/n)*(1-j/s) * dp[i+1][j+1] +1)/(1-i/n*j/s)
29
30 */
31 double dp[1000 + 10][1000 + 10];
32 int main()
33 {
34
35     int n, s;
36     while (scanf("%d%d", &n, &s) != EOF)
37     {
38         memset(dp, 0, sizeof(dp));
39         dp[n][s] = 0;
40         for (int i = n; i >= 0; --i)
41         {
42             for (int j = s; j >= 0; --j)
43             {
44                 if (i == n &&j == s)continue;
45                 dp[i][j] += (1 - (double)i / n)*j / s*dp[i + 1][j] + (double)i / n*(1 - (double)j / s)*dp[i][j + 1] + (1 - (double)i / n)*(1 - (double)j / s)*dp[i + 1][j + 1] + 1;
46                 dp[i][j] /= (1 - (double)i / n*j / s);
47             }
48         }
49         printf("%.4lf\n", dp[0][0]);
50     }
51     return 0;
52 }

hdu4405

给我们n+1个格子, 标号0到n,一个人初始在位置0,然后丢骰子向前走,

然后又给定m个 a b , 表示到了位置a,能够到飞到位置b而不需要丢骰子

问走到>=n的位置 需要丢骰子的期望次数

设dp[i] 为从位置i到>=n的位置需要丢骰子的期望次数

dp[i>=n] = 0

dp[i] = 1/6 * dp[i+1] + 1/6*dp[i+2] + ... + 1/6 * dp[i+6]

如果位置i+k  能够飞行, 那么应该用飞行过后的位置的期望带入去算

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 #pragma comment(linker, "/STACK:1024000000,1024000000")
16 typedef long long LL;
17 const int INF = 1<<30;
18 /*
19 dp[i>=n] = 0;
20 dp[i] = dp[i+k] * 1/6
21 */
22 double dp[100000 + 10];
23 int hs[100000 + 10];
24 int main()
25 {
26     int n, m;
27     int x, y;
28     while (scanf("%d%d", &n, &m), n)
29     {
30         memset(dp, 0, sizeof(dp));
31         memset(hs, 0, sizeof(hs));
32         for (int i = 0; i < m; ++i)
33         {
34             scanf("%d%d", &x, &y);
35             hs[x] = y;
36         }
37         for (int i = n-1; i >= 0; --i)
38         {
39             dp[i] = 1;
40             for (int k = 1; k <= 6; ++k)
41             {
42                 if (hs[i + k] != 0)
43                 {
44                     int t = i + k;
45                     while (hs[t] != 0)//找到飞行的最终位置, 因为能够多次飞行
46                     {
47                         t = hs[t];
48                     }
49                     dp[i] += dp[t] / 6;
50                 }
51                 else
52                     dp[i] += dp[i + k] / 6;
53             }
54         }
55         printf("%.4lf\n", dp[0]);
56     }
57     return 0;
58 }

hdu3853

一个人在迷宫的位置(1,1)  要逃到 迷宫的位置(n,m)

在位置(i,j) 需要2魔力去开启传送阵, 有p1的概率是留在原地, p2的概率往右走,p3的概率往下走

问我们逃到迷宫的位置(n,m)需要的魔力的期望

dp[i][j] = p1 * dp[i][j] + p2*dp[i][j+1]  + p3*dp[i+1][j] + 2

dp[i][j] =  ( p2*dp[i][j+1]  + p3*dp[i+1][j] + 2 ) / (1-p1)

还有一个坑是如果某点停留在原地的概率为1, 这是允许的,   那么肯定所有的点都不会到达这一点,否则答案就会很大,不符合题目所说的

所以应该讲该点的dp[i][j]置为0, 而不应该去计算(万一计算出来很大呢)不然会影响之后的值,  因为虽然走到该点的概率是0, 但是浮点数毕竟有误差。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 #pragma comment(linker, "/STACK:1024000000,1024000000")
16 typedef long long LL;
17 const int INF = 1<<30;
18 /*
19 dp[i][j] = 2 + dp[i][j+1] * p[i][j][1] + dp[i+1][j] * p[i][j][2] + dp[i][j] * p[i][j][0]
20 dp[i][j] = (2 + dp[i][j+1]*p[i][j][1] + dp[i+1][j] * p[i][j][2])/(1-P[i][j][0]);
21 */
22 const int N = 1000 + 10;
23 double p[N][N][3];
24 double dp[N][N];
25 int main()
26 {
27     int n, m;
28     while (scanf("%d%d", &n, &m) != EOF)
29     {
30         for (int i = 1; i <= n; ++i)
31         for (int j = 1; j <= m; ++j)
32         for (int k = 0; k < 3; ++k)
33             scanf("%lf", &p[i][j][k]);
34         dp[n][m] = 0;
35         for (int i = n; i >= 1; --i)
36         {
37             for (int j = m; j >= 1; --j)
38             {
39                 if (i == n &&j == m)
40                     continue;
41                 if (fabs(1 - p[i][j][0]) <= 1e-5)//如果该点停留在原地的概率为1, 这是允许的,   那么肯定所有的点都不会到达这一点,否则答案就会很大,不符合题目所说的
42                 {
43                     dp[i][j] = 0;
44                     continue;
45                 }
46                 dp[i][j] = (p[i][j][1] * dp[i][j + 1] + p[i][j][2] * dp[i + 1][j]) / (1 - p[i][j][0]) + 2/(1-p[i][j][0]);
47             }
48         }
49         printf("%.3lf\n", dp[1][1]);
50     }
51     return 0;
52 }

时间: 2024-10-05 21:59:01

期望dp专题的相关文章

DP专题

DP专题 1. 背包模型 2. 子序列模型 3. 递推DP 4. 区间DP 5. 树形DP 6. 状压DP 学习资料:位操作基础篇之位操作全面总结 如何快速取得一个二进制状态的所有子状态 7. 概率DP 学习资料:简说期望类问题的解法 等等.......

【bzoj4872】[Shoi2017]分手是祝愿 数论+期望dp

题目描述 Zeit und Raum trennen dich und mich. 时空将你我分开. B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态,下标为从 1 到 n 的正整数.每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,游戏的目标是使所有灯都灭掉.但是当操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被改变,即从亮变成灭,或者是从灭变成亮.B 君发现这个游戏很难,于是想到了这样的一个

HDOJ 1145 So you want to be a 2n-aire? 期望DP

期望DP So you want to be a 2n-aire? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 267    Accepted Submission(s): 197 Problem Description The player starts with a prize of $1, and is asked a seq

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

题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由于得到每张卡片的状态不知道,所以用状态压缩,dp[i] 表示这个状态时,要全部收齐卡片的期望. 由于有可能是什么也没有,所以我们要特殊判断一下.然后就和剩下的就简单了. 另一个方法就是状态压缩+容斥,同样每个状态表示收集的状态,由于每张卡都是独立,所以,每个卡片的期望就是1.0/p,然后要做的就是要去重,既然

Topcoder SRM656div1 250 ( 期望DP )

Problem Statement    Charlie has N pancakes. He wants to serve some of them for breakfast. We will number the pancakes 0 through N-1. For each i, pancake i has width i+1 and deliciousness d[i].Charlie chooses the pancakes he is going to serve using t

期望dp 知识点

求期望dp有两种类型 1.概率dp 2.高斯消元 相关知识点可以看这里  一篇很好的文章  http://kicd.blog.163.com/blog/static/126961911200910168335852/ http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710606.html 高斯消元  http://wenku.baidu.com/link?url=Q8ES7wreJk3et-VrHtp6CVNuyqX18YdB3c841-o

string (KMP+期望DP)

Time Limit: 1000 ms   Memory Limit: 256 MB Description  给定一个由且仅由字符 'H' , 'T' 构成的字符串$S$. 给定一个最初为空的字符串$T$ , 每次随机地在$T$的末尾添加 'H' 或者 'T' . 问当$S$为$T$的后缀时, 在末尾添加字符的期望次数. Input 输入只有一行, 一个字符串$S$. Output 输出只有一行, 一个数表示答案. 为了防止运算越界, 你只用将答案对$10^9+7$取模. Sample Inp

【期望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为转移的花费. 最后输出初始位置

【BZOJ2510】弱题 期望DP+循环矩阵乘法

[BZOJ2510]弱题 Description 有M个球,一开始每个球均有一个初始标号,标号范围为1-N且为整数,标号为i的球有ai个,并保证Σai = M. 每次操作等概率取出一个球(即取出每个球的概率均为1/M),若这个球标号为k(k < N),则将它重新标号为k + 1:若这个球标号为N,则将其重标号为1.(取出球后并不将其丢弃) 现在你需要求出,经过K次这样的操作后,每个标号的球的期望个数. Input 第1行包含三个正整数N,M,K,表示了标号与球的个数以及操作次数. 第2行包含N个