概率期望讲解

一、概率基本知识

  1. 条件概率:B发生的情况下A发生的概率

P ( A ∣ B ) = P ( A B ) P ( B ) P(A|B)=\frac{P(AB)}{P(B)} P(AB)=P(B)P(AB)

  1. 划分样本的概率

P ( A ) = ∑ i = 1 n P ( A ∣ B i ) P(A)=\sum_{i=1}^{n}{P(A|B_i)} P(A)=i=1nP(ABi)

  1. 贝叶斯公式

P ( B i ∣ A ) = P ( B i ) P ( A ∣ B i ) P ( A ) P(B_i|A)=\frac{P(B_i)P(A|B_i)}{P(A)} P(BiA)=P(A)P(Bi)P(ABi)

  1. 古典概型和几何概型
  2. 期望和
    期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E ( a A + b B + . . . ) = a E ( A ) + b E ( B ) + . . . E(aA+bB+...) = aE(A) + bE(B) +... E(aA+bB+...)=aE(A)+bE(B)+...

二、ACM的概率题目

	概率DP和递推、正常的概率计算;可以和各种数据结构结合.
  1. 概率DP

    概率dp分有环和无环两种,基本都是全概率公式的应用

    无环dp
    1. POJ2096
      原文地址
      题意
      一个软件有s个子系统,会产生n种bug。
      某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
      求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
      发现一个bug,出现在某个子系统的概率是1/s,属于某种类型的概率是1/n。
      解法:
      dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。
      显然,dp[n][s]=0,因为已经达到目标了。而dp[0][0]就是我们要求的答案。
      dp[i][j]状态可以转化成以下四种:
      dp[i][j] 发现一个bug属于已经找到的i种bug和j个子系统中
      dp[i+1][j] 发现一个bug属于新的一种bug,但属于已经找到的j种子系统
      dp[i][j+1] 发现一个bug属于已经找到的i种bug,但属于新的子系统
      dp[i+1][j+1]发现一个bug属于新的一种bug和新的一个子系统
      以上四种的概率分别为:
      p 1 = i ∗ j / ( n ∗ s ) p1 = i*j / (n*s) p1=ij/(ns)
      p 2 = ( n − i ) ∗ j / ( n ∗ s ) p2 = (n-i)*j / (n*s) p2=(ni)j/(ns)
      p 3 = i ∗ ( s − j ) / ( n ∗ s ) p3 = i*(s-j) / (n*s) p3=i(sj)/(ns)
      p 4 = ( n − i ) ∗ ( s − j ) / ( n ∗ s ) p4 = (n-i)*(s-j) / (n*s) p4=(ni)(sj)/(ns)
      又有:期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E ( a A + b B + . . . ) = a E ( A ) + b E ( B ) + . . . E(aA+bB+...) = aE(A) + bE(B) +... E(aA+bB+...)=aE(A)+bE(B)+...
      所以:
      d p [ i , j ] = p 1 ∗ d p [ i , j ] + p 2 ∗ d p [ i + 1 , j ] + p 3 ∗ d p [ i , j + 1 ] + p 4 ∗ d p [ i + 1 , j + 1 ] + 1 dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1 dp[i,j]=p1dp[i,j]+p2dp[i+1,j]+p3dp[i,j+1]+p4dp[i+1,j+1]+1
      整理得:
      d p [ i , j ] = 1 + p 2 ∗ d p [ i + 1 , j ] + p 3 ∗ d p [ i , j + 1 ] + p 4 ∗ d p [ i + 1 , j + 1 ] 1 − p 1 \begin{aligned} dp[i,j] & = \frac{ 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1]}{1-p1 } \end{aligned} dp[i,j]=1p11+p2dp[i+1,j]+p3dp[i,j+1]+p4dp[i+1,j+1]
    #include <cstdio>
    #include <iostream>
     
    using namespace std;
     
    double dp[1005][1005];
     
    int main()
    {
        int n, s, ns;
     
        cin >> n >> s;
        ns = n*s;
        dp[n][s] = 0.0;
        for (int i = n; i >= 0; i--)
            for (int j = s; j >= 0; j--)
            {
                if ( i == n && j == s ) continue;
                dp[i][j] = ( ns + (n-i)*j*dp[i+1][j] + i*(s-j)*dp[i][j+1] + (n-i)*(s-j)*dp[i+1][j+1] )/( ns - i*j );
            }
        printf("%.4lf\n", dp[0][0]);
     
        return 0;
    }
    
    有环dp
    1. HDU4035(化简类型)
      题意
      有N(2 ≤ N ≤ 10000)个房间和一堆双向边(不存在环)形成了一棵树,每个房间有 k i k_i ki e i e_i ei两个值,分别代表回到房间1和游戏结束的概率,求游戏结束时通过的边数的期望。
      从结点1出发,开始走,在每个结点 i i i都有3种可能:

      1. 回到结点1处(概率为 k i k_i ki
      2. 走出迷宫 (概率为 e i e_i ei
      3. 和该点相连有m条边,随机走一条4

      求:走出迷宫所要走的边数的期望值。

      解法
      E [ i ] E[i] E[i]为在节点 i i i处,要走出迷宫所要走的边数的期望。 E [ 1 ] E[1] E[1]即为所求。
      因为每步走都有三种可能,所以推出的公式应该有三部分:
      节 点 i 的 相 邻 节 点 数 : x i i 的 父 亲 节 点 : f a i i 的 儿 子 节 点 集 合 : N i E [ i ] = k i ∗ E [ 1 ] + e i ∗ 0 + ( 1 − k i − e i ) ∗ ( 1 x i ∗ ( ∑ j ∈ N i E [ j ] + E [ f a i ] ) + 1 ) 特 殊 的 , 对 于 叶 节 点 有 : E [ i ] = k i ∗ E [ 1 ] + ( 1 − k i − e i ) ∗ ( E [ f a i ] + 1 ) \begin{aligned} &节点i的相邻节点数:x_i\\ &i的父亲节点:fa_i\\ &i的儿子节点集合:N_i\\ &E[i] = k_i*E[1]+e_i*0+(1-k_i-e_i)*(\frac{1}{x_i}*(\sum_{j\in N_i}E[j]+E[fa_i])+1) \\ &特殊的,对于叶节点有:\\ &E[i]=k_i*E[1]+(1-k_i-e_i)*(E[fa_i]+1) \end{aligned} ixiifaiiNiE[i]=kiE[1]+ei0+(1kiei)(xi1(jNiE[j]+E[fai])+1)E[i]=kiE[1]+(1kiei)(E[fai]+1)

      分析:发现叶节点 j j j E [ j ] E[j] E[j]是关于 E [ 1 ] E[1] E[1] E [ i ] E[i] E[i]的函数,再递推下去可将方程化简成 E [ 1 ] E[1] E[1]的方程。

      设 对 每 个 结 点 : E [ i ] = A i ∗ E [ 1 ] + B i ∗ E [ f a i ] + C i 对 于 非 叶 子 结 点 i , 设 j 为 i 的 孩 子 结 点 , 则 ∑ E [ j ] = ∑ ( A j ∗ E [ 1 ] + B j ∗ E [ f a j ] + C j ) = ∑ ( A j ∗ E [ 1 ] + B j ∗ E [ i ] + C j ) 带 入 上 面 的 式 子 得 ( 1 − ( 1 − k i − e i ) x i ∗ ∑ B j ) ∗ E [ i ] = ( k i + ( 1 − k i − e i ) / x i ∗ ∑ A j ) ∗ E [ 1 ] + ( 1 − k i − e i ) / x i ∗ E [ f a i ] + ( 1 − k i − e i ) + ( 1 − k i − e i ) / x i ∗ ∑ C j ; 由 此 可 得 A i = k i + ( 1 − k i − e i ) / x i ∗ ∑ A j 1 − ( 1 − k i − e i ) / x i ∗ ∑ B j B i = ( 1 − k i − e i ) / x i 1 − ( 1 − k i − e i ) / x i ∗ ∑ B j C i = ( 1 − k i − e i ) + ( 1 − k i − e i ) / x i ∗ ∑ C j 1 − ( 1 − k i − e i ) / x i ∗ ∑ B j 对 于 叶 子 结 点 A i = k i ; B i = 1 − k i − e i ; C i = 1 − k i − e i ; 从 叶 子 结 点 开 始 , 直 到 算 出 A 1 , B 1 , C 1 ; E [ 1 ] = A 1 ∗ E [ 1 ] + B 1 ∗ 0 + C 1 ; 所 以 E [ 1 ] = C 1 / ( 1 − A 1 ) ; 若 A 1 趋 近 于 1 则 无 解 . . . \begin{aligned} &设对每个结点:E[i] = A_i*E[1] + B_i*E[fa_i] + C_i\\ & 对于非叶子结点i,设j为i的孩子结点,则\\ &∑E[j]\\ & = ∑(A_j*E[1] + B_j*E[fa_j] + C_j)\\ &= ∑(A_j*E[1] + B_j*E[i] + C_j)\\ &带入上面的式子得\\ & (1 - \frac{(1-ki-ei)}{x_i}*∑Bj)*E[i] = \\ &(ki+(1-ki-ei)/x_i*∑Aj)*E[1] +\\& (1-ki-ei)/x_i*E[fa_i] +\\& (1-ki-ei) + (1-ki-ei)/x_i*∑Cj;\\ &由此可得\\ & A_i = \frac{ k_i+(1-k_i-e_i)/x_i*∑A_j } { 1 - (1-k_i-ei)/x_i*∑B_j}\\ &B_i = \frac{ (1-k_i-e_i)/x_i} { 1 - (1-k_i-e_i)/x_i*∑B_j}\\ &C_i =\frac{ (1-k_i-e_i)+(1-k_i-e_i)/x_i*∑C_j }{ 1 - (1-k_i-e_i)/x_i*∑B_j}\\ &对于叶子结点\\ &A_i = k_i;\\ &B_i = 1 - k_i - e_i;\\ &C_i = 1 - k_i - e_i;\\ & 从叶子结点开始,直到算出 A_1,B_1,C_1;\\ & E[1] = A_1*E[1] + B_1*0 + C_1;\\ &所以\\ & E[1] = C_1 / (1 - A_1);\\ & 若 A_1趋近于1则无解...\\ \end{aligned} E[i]=AiE[1]+BiE[fai]+CiijiE[j]=(AjE[1]+BjE[faj]+Cj)=(AjE[1]+BjE[i]+Cj)(1xi(1kiei)Bj)E[i]=(ki+(1kiei)/xiAj)E[1]+(1kiei)/xiE[fai]+(1kiei)+(1kiei)/xiCj;Ai=1(1kiei)/xiBjki+(1kiei)/xiAjBi=1(1kiei)/xiBj(1kiei)/xiCi=1(1kiei)/xiBj(1kiei)+(1kiei)/xiCjAi=ki;Bi=1kiei;Ci=1kiei;A1,B1,C1;E[1]=A1E[1]+B10+C1;E[1]=C1/(1A1);A11...

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    #include<math.h>
    #include<vector>
    using namespace std;
    const int MAXN=10010;
    const double eps=1e-9;//这里1e-8会WA。设为1e-9和1e-10可以
    double k[MAXN],e[MAXN];
    double A[MAXN],B[MAXN],C[MAXN];
    
    vector<int>vec[MAXN];//存树
    
    bool dfs(int t,int pre)//t的根结点是pre
    {
        int m=vec[t].size();//点t的度
        A[t]=k[t];
        B[t]=(1-k[t]-e[t])/m;
        C[t]=1-k[t]-e[t];
        double tmp=0;
        for(int i=0;i<m;i++)
        {
            int v=vec[t][i];
            if(v==pre)continue;
            if(!dfs(v,t))return false;
            A[t]+=(1-k[t]-e[t])/m*A[v];
            C[t]+=(1-k[t]-e[t])/m*C[v];
            tmp+=(1-k[t]-e[t])/m*B[v];
        }
        if(fabs(tmp-1)<eps)return false;
        A[t]/=(1-tmp);
        B[t]/=(1-tmp);
        C[t]/=(1-tmp);
        return true;
    }
    int main()
    {
       // freopen("in.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        int T;
        int n;
        int u,v;
        int iCase=0;
        scanf("%d",&T);
        while(T--)
        {
            iCase++;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)vec[i].clear();
            ///建树
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                vec[u].push_back(v);
                vec[v].push_back(u);
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%lf%lf",&k[i],&e[i]);
                k[i]/=100;
                e[i]/=100;
            }
            printf("Case %d: ",iCase);
            if(dfs(1,-1)&&fabs(1-A[1])>eps)
            {
                printf("%.6lf\n",C[1]/(1-A[1]));
            }
            else printf("impossible\n");
        }
    }
    
    1. lightoj1151(高斯消元类型)
      题意:1*100的格子地图,从1出发,要到达100,每次走的步数用掷骰子决定(正常的骰子)。如果超过了100就重新掷骰子。地图上有的格子会使你跳跃到其他格子,可能往前可能往后。问从1走到100的掷骰子的期望次数。
      解法
      d p [ i ] dp[i] dp[i] 表示从格子 i i i走出去的期望次数,则:
      当 格 子 i 可 以 传 送 : d p [ i ] = d p [ n x t [ i ] ] 当 格 子 i 不 可 以 传 送 : d p [ i ] = { 1 6 ∗ ( ∑ j = i + 1 i + 6 d p [ j ] ) + 1 , i + 6 < = 100 1 6 ∗ ( ∑ j = i + 1 100 d p [ j ] + ( i + 6 − 100 ) ∗ d p [ i ] ) + 1 , i + 6 > 100 \begin{aligned} &当格子i可以传送:dp[i] = dp[nxt[i]]\\ &当格子i不可以传送:dp[i] = \left\{\begin{matrix} & \frac{1}{6} *(\sum_{j=i+1}^{i+6}dp[j])+1, i+6<=100\\ & \frac{1}{6} *(\sum_{j=i+1}^{100}dp[j]+(i+6-100)*dp[i])+1, i+6>100 \end{matrix}\right. \end{aligned} idp[i]=dp[nxt[i]]idp[i]={61(j=i+1i+6dp[j])+1,i+6<=10061(j=i+1100dp[j]+(i+6100)dp[i])+1,i+6>100
      这题的方程就是无序的,不像上一道题是自下往上的,因为传送是无序的,所以只能用高斯消元解决。即对于 i ∈ [ 1 , 100 ] i\in[1,100] i[1,100]都可以用上述公式列一个方程,一共一百个方程一百个未知数,用高斯消元解决。
      高斯消元直接套板子就可。
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N = 120;
    #define rep(i, j, k) for(int i = (j); i <= (k); i++)
    
    const double eps = 1e-8;
    const int MAXN = 120;
    double a[MAXN][MAXN], x[MAXN];
    int var, equ;
    
    bool Gauss() {
        int i, j, k, col, max_r;
    
        for(k = 0, col = 0; k < equ && col < var; k++, col++) {
            max_r = k;
            for(i = k + 1; i < equ; i++) if(fabs(a[i][col]) > fabs(a[max_r][col])) max_r = i;
            if(fabs(a[max_r][col]) < eps) return false;
    
            if(k != max_r) {
                for(j = col; j < var; j++) swap(a[k][j], a[max_r][j]);
                swap(x[k], x[max_r]);
            }
            
            x[k] /= a[k][col];
            for(j = col + 1; j < var; j++) a[k][j] /= a[k][col];
            a[k][col] = 1;
    
            for(i = 0; i < equ; i++) if(i != k){
                x[i] -= x[k] * a[i][col];
                for(j = col + 1; j < var; j++)
                    a[i][j] -= a[k][j] * a[i][col];
                a[i][col] = 0;
            }
        }
    
        return true;
    }
    
    int to[N];
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("data.txt", "r", stdin);
            freopen("out.txt", "w", stdout);
        #endif
    
        int t;
        cin >> t;
        int Case = 1;
        equ = var = 100;
    
        while(t--) {
            int n;  cin >> n;
            memset(to, 0, sizeof to);
    
            rep(i, 1, n) {
                int a, b;
                cin >> a >> b;
                to[a] = b;
            }
    
            for(int i = 1; i <= 100; i++) {
                if(to[i] > 0) {
                    x[i - 1] = 0.0;
                    for(int j = 0; j < var - 1; j++) a[i - 1][j] = 0.0;
                    a[i - 1][i - 1] = 1.0; a[i - 1][to[i] - 1] = -1.0;
                }
                else if(i + 6 <= 100) {
                    rep(j, 0, i - 2) a[i - 1][j] = 0.0;
                    a[i - 1][i - 1] = 6.0;
                    rep(j, i, i + 5) a[i - 1][j] = -1.0;
                    rep(j, i + 6, var - 1) a[i - 1][j] = 0.0;
                    x[i - 1] = 6.0;
                }
                else if(i + 6 > 100) {
                    rep(j, 0, i - 2) a[i - 1][j] = 0.0;
                    a[i - 1][i - 1] = 100 - i;
                    rep(j, i, var - 1) a[i - 1][j] = -1.0;
                    x[i - 1] = 6.0;
                }
            }
    
            Gauss();
    
            printf("Case %d: %.10f\n", Case++, x[0]);
        }
        
        return 0;
    }
    
  2. 概率/期望计算

    题挺杂,主要是概率公式的应用。

    1. LightOJ - 1027
      题意
      n n n个门前选择一扇门出去, 然后如果第 i i i扇门的 X i X_i Xi值是正的话,你会花费 X i X_i Xi时间后出去 , 如果 X i X_i Xi是负数的话你会花费 − X i -X_i Xi时间后回到老地方,并且忘记了刚才的选择,接着继续选择, 选择一扇门的概率是等概的。求出去时间的期望。
      解法
      设期望为 P P P,那么显然 X i X_i Xi为正的期望为 X i Xi Xi,为负的期望为 P + ∣ X i ∣ P+|X_i| P+Xi
      P = ∑ i = 1 n X i < 0 ? P − X i : X i n P=\frac{\sum_{i=1}^{n}X_i<0?P-X_i:X_i}{n} P=ni=1nXi<0?PXi:Xi
      可以求得P。

    2. lightoj - 1104
      题意
      假设一年有n天,问至少有多少个人,能保证至少其中两个人的生日在同一天的概率于等于0.5。
      解法
      x x x个人的生日都不是同一天的概率: p = 1 n n − 1 n n − 2 n . . . n − x + 1 n p=\frac{1}{n}\frac{n-1}{n}\frac{n-2}{n}...\frac{n-x+1}{n} p=n1nn1nn2...nnx+1。当 p p p大于0.5就行。

    3. LightOJ - 1248
      题意
      给定一个 n 面的骰子,问看到所有的面一次的至少所需掷骰子次数的期望。
      解法
      伯努利实验,几何分布。
      几何分布(Geometric distribution)是离散型概率分布。其中一种定义为:在n次伯努利试验中,试验k次才得到第一次成功的机率。详细的说,是:前k-1次皆失败,第k次成功的概率。期望是概率的倒数。

      第一次出现第一个面的概率: p 1 = n n , 期 望 1 p 1 p_1=\frac{n}{n},期望\frac{1}{p_1} p1=nnp11
      第一次出现第二个面的概率: p 1 = n − 1 n , 期 望 1 p 2 p_1=\frac{n-1}{n},期望\frac{1}{p_2} p1=nn1p21
      第一次出现第三个面的概率: p 1 = n − 2 n , 期 望 1 p 3 p_1=\frac{n-2}{n},期望\frac{1}{p_3} p1=nn2p31
      。。。
      第一次出现第n个面的概率: p 1 = n − 1 n , 期 望 1 p n p_1=\frac{n-1}{n},期望\frac{1}{p_n} p1=nn1pn1

      E = ∑ i = 1 n 1 p i E=\sum_{i=1}^{n}\frac{1}{p_i} E=i=1npi1

    4. lightoj - 1284
      题意
      一个 X ∗ Y ∗ Z X∗Y∗Z XYZ的立方体,n次操作,每次找出一个子立方体,给出形式为 ( x 1 , y 1 , z 1 ) , ( x 2 , y 2 , z 2 ) (x_1,y_1,z_1),(x_2,y_2,z_2) (x1,y1,z1),(x2,y2,z2),代表立方体的对角定点,对于这个子立方体中的所有开关进行反转操作,刚开始所有开关都是关闭状态,问n次操作之后处于打开状态的开关的期望个数。

      解法
      总的期望个数就是每个开关期望的和。每个开关的期望就是被操作奇数次的概率和。
      于是问题首先要解决每个开关被操作的概率,也就是选在子立方体内的概率,显然对于点 ( i , j , k ) (i,j,k) (i,j,k)概率为: P = P x P y P z , P x = 1 − i − 1 X ∗ i − 1 X − X − i X ∗ X − i X , P y P z 类 似 P = P_xP_yP_z,P_x=1-\frac{i-1}{X}*\frac{i-1}{X}-\frac{X-i}{X}*\frac{X-i}{X},P_yP_z类似 P=PxPyPzPx=1Xi1Xi1XXiXXiPyPz

      接下来要求每个开关被操作奇数次的概率:显然有公式: f [ x ] = p ∗ ( 1 − f [ x − 1 ] ) + ( 1 − p ) ∗ f [ x − 1 ] , f [ x ] 表 示 选 择 了 x 次 该 开 关 为 开 的 概 率 f[x]=p*(1-f[x-1])+(1-p)*f[x-1],f[x]表示选择了x次该开关为开的概率 f[x]=p(1f[x1])+(1p)f[x1]f[x]x,该公式再化简得: f [ x ] = ( 1 − 2 p ) x + 1 2 f[x]=\frac{(1-2p)^x+1}{2} f[x]=2(12p)x+1 f [ n ] f[n] f[n]就是所求。

      最后对每个点求和即可。

三、练习

lightoj - 1317
LightOJ - 1342  
LightOJ - 1364 
LightOJ - 1395

题意:
有三个均匀的骰子,分别有k1,k2,k3个面,初始分数是0,
当掷三个骰子的点数分别为a,b,c的时候,分数清零,否则分数加上三个骰子的点数和,
当分数>n的时候结束。求需要掷骰子的次数的期望。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值