【整理】简单的数学期望和概率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
原文地址:https://www.cnblogs.com/hua-dong/p/8166093.html