zoukankan      html  css  js  c++  java
  • 概率-期望粗学

    引用:https://blog.csdn.net/auto_ac/article/details/9907881 

    很多概率题总逃不开用dp转移。
               
            期望题总是倒着推过来的,概率是正着推的,多做题就会理解其中的原因
                
                有些期望题要用到有关 概率 或 期望的常见公式或思想
           
                      遇到dp转移方程(组)中有环的,多半逃不出高斯消元(手动 和 写代码 两种)
      
                              这套题中还有道树上的dp转移,还用dfs对方程迭代解方程, 真是大开眼界了
                    
                                        当然还有与各种算法结合的题,关键还是要学会分析

                                                   当公式或计算时有除法时, 特别要注意分母是否为零

    概率:

    入门题:http://acm.hdu.edu.cn/showproblem.php?pid=3853

    题意:一开始在矩阵左上角,每次有三种可能的选择(有对应的概率)向下走、向右走、原地不动,每次都有2的消耗,问到矩阵右下角的期望消耗是多少?

    分析:设dp[i][j]表示从位置[i,j]到右下角的期望,那么dp[i][j]=dp[i][j]*(原地不动的概率)+dp[i+1][j]*(向下走的概率)+dp[i][j+1]*(向右走的概率)移项得公式

    #include<cstdio>
    using namespace std;
    const int M=1003;
    double p[M][M][5],dp[M][M];
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%lf%lf%lf",&p[i][j][1],&p[i][j][2],&p[i][j][3]);
            dp[n][m]=0;
            for(int i=1;i<=n;i++)
                dp[i][m+1]=0;
            for(int i=1;i<=m;i++)
                dp[n+1][i]=0;
            for(int i=n;i>0;i--){
                for(int j=m;j>0;j--){
                    if(p[i][j][1]==1||i==n&&j==m)
                        continue;
                    dp[i][j]=(dp[i+1][j]*p[i][j][3]+dp[i][j+1]*p[i][j][2]+2)/(1-p[i][j][1]);
                }
    
            }
            printf("%.3f
    ",dp[1][1]);
        }
        return 0;
    }
    View Code

     练习:

    题1:http://poj.org/problem?id=3744

    题意:在水平面上设置一些类似障碍的东西,然后一个人从位置1开始行动,有p的概率跳一个单位,有1-p的概率跳俩个单位,问这个人跳过全部障碍的概率是多少;

    分析:对于这个公式应该一秒就出来了,不过给定的n个障碍物的位置会达到10^8级别,所以我们用矩阵快速幂来解决(类似就菲...数列一样)构造出基矩阵就行

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    double c[2][2],b[2][2],t[2][2];
    int a[100];
    double p;
    void mul(double x[][2],double y[][2]){///return x=x*y
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                c[i][j]=0;
        for(int i=0;i<2;i++)
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++)
                c[i][j]+=x[i][k]*y[k][j];
        }
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                x[i][j]=c[i][j];
    }
    void sksm(int n){
        b[0][0]=p,    b[0][1]=1;
        b[1][0]=1.0-p,b[1][1]=0;
        t[0][0]=1,t[0][1]=0;
        t[1][0]=0,t[1][1]=1;
        while(n){
            if(n&1){
                mul(t,b);
            }
            mul(b,b);
            n>>=1;
        }
    }
    int main(){
        int n;
        while(~scanf("%d%lf",&n,&p)){
            for(int i=0;i<n;i++)
                scanf("%d",&a[i]);
            sort(a,a+n);
            double ans=1.0;
            sksm(a[0]-1);
            ans*=(1-t[0][0]);
            for(int i=1;i<n;i++){
                sksm(a[i]-a[i-1]-1);
                ans*=(1-t[0][0]);
            }
            printf("%.7f
    ",ans);
        }
        return 0;
    }
    View Code

     题2:http://poj.org/problem?id=3071

    题意:模拟足球比赛淘汰制,给定每个球队战胜别的球队的概率,输出能最后胜出的球队的编号

    分析:用dp算出所有队伍每次晋级的dp值依次往上推就行

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    
    using namespace std;
    typedef long long ll;
    const int M=266;
    double a[M][M],dp[M],c[M];
    int main(){
        int t;
        while(~scanf("%d",&t)){
            if(t==-1)
                break;
            int n=1;
            for(int i=1;i<=t;i++)
                n<<=1;
            //cout<<n<<endl;
            for(int i=1;i<=n;i++){
                dp[i]=1.0;
                for(int j=1;j<=n;j++)
                    scanf("%lf",&a[i][j]);
            }
            int nowlen=1;
            for(int i=1;i<=t;i++){
                for(int j=1;j<=n;j++)
                    c[j]=dp[j],dp[j]=0;
                nowlen<<=1;
                for(int j=1;j<=n;j+=nowlen){
                    
                    int l=j,r=j+nowlen-1;
                    int midd=(l+r)>>1;
                    for(int k=l;k<=midd;k++){
                        for(int p=midd+1;p<=r;p++)
                            dp[k]+=c[k]*a[k][p]*c[p];
                    }
                    for(int k=midd+1;k<=r;k++){
                        for(int p=l;p<=midd;p++)
                            dp[k]+=c[k]*a[k][p]*c[p];
                    }
                }
            }    
            double maxx=0;
            int ansi=1;
            for(int i=1;i<=n;i++){
                if(maxx-dp[i]<0){
                    maxx=dp[i];
                    ansi=i;
                }
            //    printf("%.7f
    ",dp[i]);
            }
            printf("%d
    ",ansi);
        }
        return 0;
    }
    View Code

    题3:http://codeforces.com/problemset/problem/148/D

    题意:有w只白鼠,b只黑鼠,问先手抓到第一次白鼠的概率,其中后手抓完后在所有老鼠中会随机地跑掉一只

    分析:记忆化搜索

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e3+3;
    int vis[M][M];
    double dp[M][M];
    double dfs(int noww,int nowb){
        if(noww<=0)
            return 0;
        if(nowb<=0)
            return 1;
        if(vis[noww][nowb]==1)
            return dp[noww][nowb];
        vis[noww][nowb]=1;
        double &res=dp[noww][nowb];
        res=noww*1.0/(noww+nowb);///这次取到白色
        if(nowb>=2){
            ///失败俩次来捉黑鼠
            double x=nowb*1.0/(noww+nowb);
            nowb--;
            x*=nowb*1.0/(noww+nowb);
            nowb--;
            ///             白鼠溜了                            黑鼠溜了
            res+=x*(noww*1.0/(noww+nowb)*dfs(noww-1,nowb))+x*(nowb*1.0/(nowb+noww)*dfs(noww,nowb-1));
        }
        return res;
    }
    int main(){
        double n,m;
        scanf("%lf%lf",&n,&m);
        printf("%.9f
    ",dfs(n,m));
        return 0;
    }
    View Code

     期望:

    题1:https://ac.nowcoder.com/acm/contest/697/A

    分析:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1000000007;
    const int M=2e5+5;
    ll dp[M];
    ll ksm(ll a,ll b){
        ll t=1;
        while(b){
            if(b&1)
                t=t*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return t;
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            ll x,y;
            scanf("%I64d%I64d",&x,&y);
            dp[i]=(dp[i-1]+1)*y%mod*ksm(x,mod-2)%mod;
        }
        printf("%I64d",dp[n]);
    }
    View Code
  • 相关阅读:
    Checked Exception & Unchecked Exception
    Spring事务:调用同一个类中的方法
    SpringMVC接收checkbox传值
    Java String 学习
    写给大忙人的JavaSE 8
    Spring in Action 4th 学习笔记 之 AOP
    Spring in Action 4th 学习笔记
    spring只是一个框架
    lambda小结
    电感的Q值
  • 原文地址:https://www.cnblogs.com/starve/p/12005857.html
Copyright © 2011-2022 走看看