zoukankan      html  css  js  c++  java
  • 【整理】简单的数学期望和概率DP

    • 数学期望 P=Σ每一种状态*对应的概率。
    • 因为不可能枚举完所有的状态,有时也不可能枚举完,比如抛硬币,有可能一直是正面,etc。在没有接触数学期望时看到数学期望的题可能会觉得很阔怕(因为我高中就是这么认为的,对不起何老板了QwQ),避之不及。 但是现在发现大多数题就是手动找公式或者DP推出即可,只要处理好边界,然后写好方程,代码超级简短。与常规的求解不同,数学期望经常逆向推出。
    • 比如常规的dp[x]可能表示到了x这一状态有多少,最后答案是dp[n]。而数学期望的dp[x]一般表示到了x这一状态还差多少,最后答案是dp[0]

    具体的看下面的题型吧,看完应该就有感觉了。

    •  最后面几道是DP,感觉和数学期望关系不大,不看也罢。

    一:Uva12230Crossing Rivers (数学期望)

    题目大意:
    有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,
    给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v。船会往返在河的两岸,人到达河岸时,
    船的位置是随机的(往返中)。问说人达到公司所需要的期望时间。
    思路:
    
    1,过每条河最坏的情况是t=3*L/v; 即去的时候船刚刚走。
    2,过没条河最优的情况是t=L/v;    即去的时候船刚刚来。
    3,由于船是均匀发布的,符合线性性质,所以平均下来,过每条河的时间t=2*L/v。

    (是不是感觉看完后豁然开朗。。。。。。发自内心地说道:原来是尼玛这样一个题,当然这个题并不典型)

    二:SPOJ Favorite Dice(数学期望)

    题意:
    
    甩一个n面的骰子,问每一面都被甩到的次数期望是多少。
    思路:
    
    比较简单常见,公式:初始化dp[]=0;  dp[i]=i/n*dp[i]+(n-i)/n*dp[i+1]+1;  化简逆推即可。  求的是dp[0];

    三:SGU495Kids and Prizes(数学期望||概率DP||公式)

    题意:
    
    有n个奖品,m个人排队来选礼物,对于每个人,他打开的盒子,可能有礼物,也有可能已经被之前的人取走了,然后把盒子放回原处。为最后m个人取走礼物的期望。
    思路:
    
    排队取,第1个人取到1个,dp[1]=1;后面的人dp[i]=p取到礼物盒子+dp前面的取到礼物盒子=(n-dp[i-1])/n + dp[i-1];
    
    当然,也可以化简为公式   printf("%.10lf
    ",n*1.0*(1-pow((n-1)*1.0/n,m)));  

     

    四:ZOJ3640Help Me Escape(师傅逃亡系列•一) (我自己的逃亡三题)

    题意:
    
    师傅被妖怪抓走了。有n个妖怪,每个妖怪有一个固定的战斗力c[],师傅也有一个初始战斗力f0。
    每天,师傅会随机选择一个妖怪决斗,如果打得赢ft
    >c[],就可以逃出去,逃出去要t[]天,毕竟超人不会飞;
    否则,师傅会不甘心,当天他会拿出秘籍练功,将自己变强,f(t+1)=f(t)+c[],第二天寻找下一次机会。
    问师傅能够逃脱可怕的妖怪,继续追求去印度吃手抓饼的梦想的天数的数学期望day。
    思路:
    
    设dp[F]是战斗力为F时,逃离的天数期望。(答案是dp[f])。则有公式。
    
    dp[F]= Σ 1/n * t[i]              ,F>c[[i]
    
               +∑ 1/n * dp[F+c[i]]   ,F<=c[i]

    (第一题是水的,这一题像样一点,列方程。)

     

    五:HDU4035 Maze(师傅逃亡系列•二)(循环型 经典的数学期望)

    题意:
    
    师傅又被抓了,师傅现在在一个里。第一天他在1号节点;对于每一个节点,
    有三种可能,一是被妖怪杀死ki,二是被徒儿救走ei,三是第二天等概率地走到相邻的一个节点。
    问师傅被救走的天数的期望,不能被救走输出“impossible”。
    思路:
    
    上一个题,由于是单调的,没有后续性,所以可以记忆化搜索或者DP解决。
    这个题存在后续性,举个例子。如果求从s号节点逃出去的期望dp[s],那么dp[s]和s的子节点和s的父节点有关,而欲求s的子节点时,子节点又和父节点s有关。。。 这个时候就需要我们找一个办法来排除后续性。大概就是找一个很牛逼的公式。这个公式本来是和后续性有关,但是公式之间抵消的后续性。
    设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
    
        叶子结点:
        E[i] = ki*E[1] + ei*0 + (1-ki-ei)*(E[father[i]] + 1);
             = ki*E[1] + (1-ki-ei)*E[father[i]] + (1-ki-ei);
    
        非叶子结点:(m为与结点相连的边数)
        E[i] = ki*E[1] + ei*0 + (1-ki-ei)/m*( E[father[i]]+1 + ∑( E[child[i]]+1 ) );
             = ki*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei)/m*∑(E[child[i]]) + (1-ki-ei);
    设对每个结点:E[i] = Ai*E[1] + Bi*E[father[i]] + Ci;
    对于非叶子结点i,设j为i的孩子结点,则
        ∑(E[child[i]]) = ∑E[j]
                       = ∑(Aj*E[1] + Bj*E[father[j]] + Cj)
                       = ∑(Aj*E[1] + Bj*E[i] + Cj)
        带入上面的式子得
        (1 - (1-ki-ei)/m*∑Bj)*E[i] = (ki+(1-ki-ei)/m*∑Aj)*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei) + (1-ki-ei)/m*∑Cj;
        由此可得
        Ai =        (ki+(1-ki-ei)/m*∑Aj)   / (1 - (1-ki-ei)/m*∑Bj);
        Bi =        (1-ki-ei)/m            / (1 - (1-ki-ei)/m*∑Bj);
        Ci = ( (1-ki-ei)+(1-ki-ei)/m*∑Cj ) / (1 - (1-ki-ei)/m*∑Bj);
    
        对于叶子结点
        Ai = ki;
        Bi = 1 - ki - ei;
        Ci = 1 - ki - ei;
    
        从叶子结点开始,直到算出 A1,B1,C1;
    
        E[1] = A1*E[1] + B1*0 + C1;
        所以
        E[1] = C1 / (1 - A1);
        若 A1趋近于1则无解...

     

    六:HDU3853LOOPS (师傅逃亡系列•三)(基础概率DP) 

    题意:
    
    你知道,师傅经常被抓,这次又被抓到一个矩阵里面,最开始他在Map[1][1],出口在Map[n][m];
    每一次他会消耗两颗神丹,然后每一个格子,有一定概率留在原地,有一定概率向下走一格,有一定概率向右走一格。。。求师傅逃出去的神丹消耗期望。
    思路:
    
    这次的逃亡很好想,没有前两次那样需要逆推或者求公式。聪明的你不如手动算一下。实在不行还可以参考下面的题目。

     

    七:ZOJ3551Bloodsucker (数学期望)

    题意:
    
    开始有一个吸血鬼,n-1个平民百姓。每天一个百姓被感染的概率可求,问每个人都变成吸血鬼的天数期望
    思路:
    
    一般期望题逆推,设dp[i]是目前已经有i个吸血鬼,所有人变成吸血鬼的期望。则dp[n]=0;答案是dp[1]。(注意这里dp代表的什么

    每一个dp[i]的感染概率可求是p[]=2.0*(n-i)*i/(n-1)/n*p; 则可得递推公式: dp[i] = (dp[i+1]*p[]+1)/p[];

    八:ZOJ3329One Person Game(循环型 数学期望)

     题意:
    
    有三个骰子,面值分别是k1,k2,k3。每次扔出的值之和加到ans上,问多少次才能ans>n;当然,当遇到k1=a,k2=b,k3=c时,ans=0;重新开始累加。
    思路:
    
    和之前第五题Maze一个题型。写出的公式是有后续性的。我们需要弄一个递推公式,消去后续性。(当然循环的话高斯消元也可以做。)
    设dp[i]表示达到i分时到达目标状态的期望,pk为投掷k分的概率,p0为回到0的概率
    则dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;
    都和dp[0]有关系,而且dp[0]就是我们所求,为常数
    设dp[i]=A[i]*dp[0]+B[i];
    代入上述方程右边得到:
    dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1
         =(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;
         明显A[i]=(∑(pk*A[i+k])+p0)
         B[i]=∑(pk*B[i+k])+1
         先递推求得A[0]和B[0].
         那么  dp[0]=B[0]/(1-A[0]);

    大概就是这个样子。  

     

    九:CF 148D D. Bag of mice (概率DP||数学期望)

     题意:
    
    一对情侣开房玩抓老鼠游戏,老鼠有黑白两色,女的为先手,先抓到白老鼠胜。
    特别的,男的每抓一只老鼠后,还会随机放走一只老鼠。问女的赢的概率是多少。如果输了,后果会很严重,当天晚上只能睡沙发。
    思路:
    
    dp[i][j]为当前状态,有i只白老鼠,j只黑老鼠,女的赢的概率。那么dp[][] = 这一次赢 + 以后赢=   i/(i+j) +  。。。具体见代码。

      

    十:POJ3682King Arthur's Birthday Celebration(数学期望||概率DP)

    题意:
    
    有一个富豪,他决定每天撒钱,并且抛硬币,第一天1块钱,第二天3块钱,第三天5块,直到他抛到硬币向上的数量为K。
    
    求天数期望和钱期望。
    思路:
    
    天数期望dp很好求,公式一推,代码一敲。钱期望money没想出来,我开始想难道是用第x天结束的期望乘第x天的钱,累加,直到x天的期望乘钱小于0.0001

    但是参考了下别人的公式,反正自己是没想出来。 天数:dp[i]
    =dp[i]*(1-p)+dp[i-1]*p+1,化简:dp[i]=dp[i-1]+1/p; money:money[i] = p(money[i-1]+ 2 *(dp[i-1]+1)-1) + (1-p)(money[i] + 2 * (dp[i]+1)-1)。

    化简:money[i]=money[i-1]+2*dp[i-1]-2*dp[i]+(1+2*dp[i])/p; 问题: 可以用巴斯卡分布?二项分布???给数学跪了 http://blog.csdn.net/nmfloat/article/details/50650489

    十一: POJ2151Check the difficulty of problems (组合数学||概率DP)

    题意:
    
    一套题,有T个题,M个人应考,已知每个人做来某题的概率。问X的概率。X满足,每个考生至少做来一道题。至少有一人做的题不少于N道。
    思路:
    
    不算是很典型的概率DP,更像是一道简单数学题。
    
    可以把所有考生都至少做来一道题的概率减去 每个人都做来1到n-1道题的概率。
    
    p=[(1-x11)*(1-x12)(..) ] * [(1-x21)*(1-x22)(..)]*[...]     -    [...]*[...] ,这样的话,用组合数就ok了。
    
    但是这里是用的DP是思路,先把考生与考题的关系求出来,p[i][j][k] 表示第i个考试前j个题会做k道的概率。再根据题意进行DP。

    十二:HihoCoder1164 随机斐波那契(概率DP) 

    
    
    大家对斐波那契数列想必都很熟悉:
    
    a0 = 1, a1 = 1, ai = ai-1 + ai-2,(i > 1)。
    
    现在考虑如下生成的斐波那契数列:
    
    a0 = 1, ai = aj + ak, i > 0, j, k从[0, i-1]的整数中随机选出(j和k独立)。
    
    现在给定n,要求求出E(an),即各种可能的a数列中an的期望值。(1<=n<=500)
    思路:
    不说了,数据小,我暴力枚举的。

    十三:HihoCoder 1075 开锁魔法III(概率DP+组合)

    描述
    
    一日,崔克茜来到小马镇表演魔法。
    
    其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。
    初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开。崔克茜想知道最后所有盒子都被打开的概率。
    1,每个盒子都有一个入度和一个出度,以之前二分图拆点的经验来看,必然会形成很多个环。
    
    2,每个环至少选择一个盒子。
    
    3,每个环至少选择一个盒子的组合数,联想到母函数,组合数。
    
    4.自由YY。可以DP,但是误差可能大一些。可以全部求出来再除,这样误差小一些。
    
     (ps:学会了母函数再搞组合是要多一分灵感!弯的four)

     十四:BZOJ - 4318: OSU! (期望DP&Attention)

    题意:一段连续长度为L的线段贡献是L^3,求贡献的期望。 (注意期望的平方和求方的期望不一样
    思路:此类期望题都是单独算某一位的贡献,假设前一位的连续长度为g[i-1],那么很明显当前位的期望长度为 g[i]=(g[i-1]+1)*p[i];
    
    则当前为的贡献是add=g[i]^3-g[i-1]^3=3*g[i]^2-3*g[i]+1。 这三部分分别算期望即可。
    
       第一部分:3*g[i]^2,就是平方的期望(不仅仅是期望的平方那么简单),令期望的平方为数组g2,则3g2[i]=3*(g2[i-1]+2*g[i-1]+1)*p[i];
    
       第二部分:-3*g[i],其期望=-3*(g[i-1]+1)*p[i]
    
       第三部分:   1,其期望=p[i]
    
    主要就是要注意期望的平方如何去算!

     -------------------------------------------------------------分界线-----------------------------------------------------------------------------

    2019-05-12更新

    由于上诉都是一些比较简单的东西,而好像又容易被搜索到,所以加点干货。

    干货一:    反复模拟,逼近答案。

    (有的题目,由于大方向确定,我们只需要在小范围内一层一层不断逼近即可;或是随机多次也能得到比较正确的结果。

     

    CodeForces - 24D :Broken robot (高斯消元 随机)

    pro:给定N*M的矩阵,以及初始玩家位置。 规定玩家每次会等概率的向左走,向右走,向下走,问走到最后一行的期望。保留4位小数。

    sol:可以列出方程,高斯消元即可,发现是三角矩阵,O(N^2)。  也可以用反复逼近答案。 反复做,dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0  为了使逼近效果更好,我每次先左一次,再右一次。   虽然 暴力但是效率也不差。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1010;
    double dp[maxn][maxn]; int d[maxn];
    int main()
    {
        int N,M,x,y;
        scanf("%d%d%d%d",&N,&M,&x,&y);
        rep(i,1,M){
            d[i]=2;
            if(i>1) d[i]++;
            if(i<M) d[i]++;
        }
        rep(i,x+1,N){
            rep(t,1,20){
                rep(j,1,M) dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0;
                for(int j=M;j>=1;j--) dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0;
            }
        }
        printf("%.10lf
    ",dp[N][y]);
        return 0;
    }
    View Code

    干货二:    Min-Max容斥。

    (有的题目,数据量比较小,但是方程很难列出,我们可能要考虑容斥,min-max容斥是一种比较常见的容斥方式。 他解决问题的方式:假设有S个对象,求把所有东西都取到的期望,不直接求,而是通过求子集的期望,然后容斥得到结果。

     

    HDU - 4336:Card Collector(min-max容斥求期望)

    pro:题面不好看,题意很简单,就是给定S个物品,然后每次取到物品i的概率为pi,∑pi<=1; 求把所有物品都至少取到一次的期望。

    sol:  T是S的子集,我们得到每个子集T的期望,然后乘上容斥系数,累加起来就是答案。 假设我们dfs得到了S的子集T,并且得到至少取到这个子集的一个的概率p,则其期望为1/p;

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=30;
    double p[maxn],ans; int N;
    void dfs(int pos,double now,int opt)
    {
        if(pos==N+1) {
            if(opt>0){
               if(opt&1) ans+=1.0/now;
               else ans-=1.0/now;
            }
            return ;
        }
        dfs(pos+1,now,opt);
        dfs(pos+1,now+p[pos],opt+1);
    }
    int main()
    {
        while(~scanf("%d",&N)){
            for(int i=1;i<=N;i++) scanf("%lf",&p[i]);
            ans=0; dfs(1,0.0,0);
            printf("%.4lf
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Layui的省市区三级联动
    Uncaught SyntaxError: Unexpected token ','
    Cannot use 'in' operator to search for '23' in
    Linux 递归批量删除文件夹或文件的命令
    PHPstorm常用快捷键(Windows)
    Isset、empty、count、is_null的比较
    PHPstorm快捷键的学习
    Elasticsearch索引按月划分以及获取所有索引数据
    Elasticsearch入门
    java自学-流程控制语句
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8166093.html
Copyright © 2011-2022 走看看