概率期望总结

一.解题技巧:

期望题倒着推,概率正着推
经常和概率dp联系

二.例题:

**1.POJ 3744**

详解:

2.POJ - 3071 Football

代码:

#include <cstdio>
#include <cstring>
using namespace std;
const int N=(1<<7)+5;
double p[N][N],win[N][10];//每个选手进入第i轮的概率
int main()
{
    int n;
    while(scanf("%d",&n),n!=-1)
    {
        int m=1<<n;
        double maxn=0;
        int num=1;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=m;j++)
                scanf("%lf",&p[i][j]);
        }
        memset(win,0,sizeof(win));
        for(int i=1;i<=m;i++)
            win[i][0]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {//cout<<"j="<<j<<" : ";
                int len=1<<i;
                int s=j/len;
                if(j%len==0)
                    s--;
                s*=len;//cout<<s+1<<"->"<<s+len<<" ";
                int l=(j>(s+len/2)?(s+1):(s+len/2+1));
                int r=(j>s+len/2?s+len/2:s+len);
                //cout<<"l= "<<l<<" r="<<r<<" ";
                for(int k=l;k<=r;k++)//第i轮第j个选手需要比较的区间
                {
                    if(k==j)
                        continue;
                    win[j][i]+=win[j][i-1]*win[k][i-1]*p[j][k];
                }
                //cout<<win[j][i]<<endl;
                if(i==n&&win[j][i]>maxn)
                {
                    maxn=win[j][i];
                    num=j;
                }
            }
        }//cout<<maxn<<endl;
        printf("%d\n",num);
    }
    return 0;
}


3.Bag of mice CodeForces - 148D

代码:
【记忆化搜索】

#include <bits/stdc++.h>
using namespace std;
double dp[1005][1005];//到达每个状态时的概率
bool vis[1005][1005];//标记状态,避免重复搜索
double dfs(int w,int b)//每次的状态对应的都是公主取的时刻
{
    if(w<=0)//没有白色:输
        return 0;
    if(b<=0)//没有黑色:赢
        return 1;
    if(vis[w][b])
        return dp[w][b];
    vis[w][b]=1;
    double &res=dp[w][b];//下面w,b改变了
    res=1.0*w/(w+b);//或者取白色
    if(b>=2)//或者取黑色
    {
        double t=b*1.0/(w+b);//公主取黑色
        b--;
        t*=b*1.0/(w+b);//龙取黑色
        b--;
        res+=t*(w*1.0/(w+b)*dfs(w-1,b)+b*1.0/(w+b)*dfs(w,b-1));//白色跑或者黑色跑
    }
    return res;
}
int main()
{
    int w,b;
    scanf("%d%d",&w,&b);
    printf("%.9f\n",dfs(w,b));
    return 0;
}

【概率dp】
对公主而言有两种选择:
  1.取白球,获胜;
  2.取黑球,取决于后面的情况;
当选择黑球,为使公主获胜,龙必然选择黑球,那么跳出的球就有两种可能:白或黑
  白:\(dp[i][j]=1.0*j/(i+j)*1.0*(j-1)/(i+j-1)*1.0*i/(i+j-2)*dp[i-1][j-2];\)
  黑:\(dp[i][j]=1.0*j/(i+j)*1.0*(j-1)/(i+j-1)*1.0*(j-2)/(i+j-2)*dp[i][j-3];\)
边界条件:
  全为白球:\(dp[i][0]=1;\)
  全为黑球:\(dp[0][i]=0;\)

#include <bits/stdc++.h>
using namespace std;
double dp[1005][1005];
int main()
{
    int w,b;
    scanf("%d%d",&w,&b);
    for(int i=1;i<=w;i++)
        dp[i][0]=1;
    for(int i=1;i<=w;i++)
    {
        for(int j=1;j<=b;j++)
        {
            dp[i][j]=1.0*i/(i+j);//取白球
            double t=1.0*j/(i+j)*1.0*(j-1)/(i+j-1);//两者都取黑球
            if(j>=3)//跳白球
                dp[i][j]+=t*1.0*(j-2)/(i+j-2)*dp[i][j-3];
            if(i>=1&&j>=2)//跳黑球
                dp[i][j]+=t*1.0*i/(i+j-2)*dp[i-1][j-2];
        }
    }
    printf("%.9f\n",dp[w][b]);
    return 0;
}

4.Check the difficulty of problems POJ - 2151

分析:

\(dp[i][j][k]\):表示第 \(i\) 个队在前 \(j\) 题中做对 \(k\) 道的概率;(记住这种表示方法)
状态转移方程:\(dp[i][j][k]=dp[i][j-1][k-1]*p[i][j]+dp[i][j-1][k]*(1-p[i][j])\);
边界条件:\(dp[i][0][0]=1,dp[i][j][0]=\prod_{k=1}^{j}{(1-p[i][k])}\)

\(s[i][j]\):表示第 \(i\) 个队整场比赛中做出的题目数 \(\leq j\) 的概率;
\(s[i][j]=\sum_{k=0}^{j}{dp[i][m][k]}\)

\(P_1\)表示每队至少做出一题的概率,\(P_2\)表示每队做出的题目数为 \([1,n-1]\) 的概率;
\(P_1=\prod_{i=1}^{t}{(1-s[i][0])}\)
\(P_2=\prod_{i=1}^{t}{(s[i][n-1]-s[i][0])}\)

最终结果为:\(P_1-P_2\),即所有队都至少做出一道题且至少有一个队做出了 \(n\) 道题。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1005;
double dp[N][32][32],s[N][32],p[N][32];
int main()
{
    int m,t,n;
    while(scanf("%d%d%d",&m,&t,&n),m||t||n)
    {
        for(int i=1;i<=t;i++)
            for(int j=1;j<=m;j++)
                scanf("%lf",&p[i][j]);
        for(int i=1;i<=t;i++)
        {
            dp[i][0][0]=1.0;
            for(int j=1;j<=m;j++)
            {
                dp[i][j][0]=dp[i][j-1][0]*(1-p[i][j]);
                for(int k=1;k<=j;k++)
                    dp[i][j][k]=dp[i][j-1][k-1]*p[i][j]+dp[i][j-1][k]*(1-p[i][j]);
            }
        }
        for(int i=1;i<=t;i++)
        {
            for(int j=0;j<=m;j++)
            {
                s[i][j]=0;
                for(int k=0;k<=j;k++)
                    s[i][j]+=dp[i][m][k];
            }
        }
        double p1=1.0,p2=1;
        for(int i=1;i<=t;i++)
        {
            p1*=(1-s[i][0]);
            p2*=(s[i][n-1]-s[i][0]);
        }
        printf("%.3f\n",p1-p2);

    }
    return 0;
}

posted @ 2020-02-28 17:01  xzx9  阅读(177)  评论(0编辑  收藏  举报