概率期望DP

概率 \(DP\)

定义:

概率 \(DP\) 用于解决概率问题与期望问题。

一般般情况下,解决概率问题需要顺序循环,而解决期望问题使用逆序循环

如果定义的状态转移方程存在后效性问题,还需要用到 高斯消元 来优化

同时,也会结合其他转移方式进行考察:

\(DP\) 求概率:

这类题目采用顺推,难点是对状态转移方程的刻画

例题:

CF148D Bag of mice

题意

袋子里有 \(w\) 只白鼠和 \(b\) 只黑鼠 ,\(A\)\(B\) 轮流从袋子里抓,谁先抓到白色谁就赢。\(A\) 每次随机抓一只,\(B\) 每次随机抓完一只之后会有另一只随机老鼠跑出来。如果两个人都没有抓到白色则 \(B\) 赢。\(A\) 先抓,问 \(A\) 赢的概率。

分析

我们设 \(dp[i][j]\) 表示有 \(i\)\(j\) 黑时 \(A\) 的胜率,然后进行分类讨论:

  1. \(A\) 白,此时直接赢
  2. \(A\) 黑,\(B\) 出白,此时 \(B\) 必赢,所以无法转移,跳过
  3. \(A\) 黑,\(B\) 黑,跑白,此时从 \(dp[i-1][j-2]\) 转移
  4. \(A\) 黑,\(B\) 黑,跑黑,此时从 \(dp[i][j-3]\) 转移

概率应该都会算吧,就是对应颜色数量除以总数量

因此则很好列转移方程:

for(int i=1;i<=w;i++) dp[i][0]=1.0;
for(int i=1;i<=b;i++) dp[0][i]=0;
for(int i=1;i<=w;i++){
    for(int j=1;j<=b;j++){
        dp[i][j]=(db)i/(i+j);
        db a1=(db)j/(i+j),a2=(db)(j-1)/(i+j-1),a3=(db)i/(i+j-2),a4=(db)(j-2)/(i+j-2);
        if(i>=1&&j>=2) 
            dp[i][j]+=(db)a1*a2*a3*dp[i-1][j-2];
        if(j>=3) 
            dp[i][j]+=(db)a1*a2*a4*dp[i][j-3];
    }
}

注意初始化,全是白色 \(A\) 肯定赢,全黑色 \(A\) 肯定输。

POJ 3071 Football

题意:

\(2^n\) 个足球,每两个队之间有各自获胜的概率,前后之间打,赢得晋级,问哪个队夺冠概率最大?

分析

\(dp[k][i]\) 表示第 \(k\) 轮,\(i\) 获胜的概率。

转移方程还是比较好写,但是有一个判断两者是否能成为对手的标记。

if((((i-1)>>(k-1))^1)==((j-1)>>(k-1)))

如果满足这个条件,则证明两个之间是可以成为对手的.

因为两者二进制第 \([k,n]\) 位是相同的,只有 \(k-1\) 位不同,证明可以在第 \(k\) 轮成为对手。

最后判断最大值即可。

while(scanf("%d",&n)){
    memset(dp,0,sizeof(dp));
    if(n==-1) break;
    int m=1<<n;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            scanf("%lf",&now[i][j]);
        }
    }
    for(int i=1;i<=m;i++) dp[0][i]=1;
    for(int k=1;k<=n;k++){
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if((((i-1)>>(k-1))^1)==((j-1)>>(k-1))){
                    dp[k][i]+=dp[k-1][i]*dp[k-1][j]*now[i][j];
                }
    }
    double maxx=0.0; int ans=0;
    for(int i=1;i<=m;i++) if(dp[n][i]>maxx){maxx=dp[n][i],ans=i;}
    cout<<ans<<endl;
}
posted @ 2021-10-10 13:13  Evitagen  阅读(65)  评论(0编辑  收藏  举报