• 期望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
    ", dp[0][0]);
    50     }
    51     return 0;
    52 }
    View Code

    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
    ", dp[0]);
    56     }
    57     return 0;
    58 }
    View Code

    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
    ", dp[1][1]);
    50     }
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    谈一谈循环的性能提升
    Web前端性能优化的9大问题
    随机获取一种颜色值的三种方法
    ES6还是ES2015?
    history.back(-1)和history.go(-1)的区别
    关于overflow-y:scroll ios设备不流畅的问题
    前端如何压缩图片
    【转】理解JavaScript之闭包
    关于如何给数字排序
    本地缓存localstorage使用
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4657293.html
Copyright © 2020-2023  润新知