概率期望DP
概率 \(DP\)
定义:
概率 \(DP\) 用于解决概率问题与期望问题。
一般般情况下,解决概率问题需要顺序循环,而解决期望问题使用逆序循环
如果定义的状态转移方程存在后效性问题,还需要用到 高斯消元 来优化
同时,也会结合其他转移方式进行考察:
\(DP\) 求概率:
这类题目采用顺推,难点是对状态转移方程的刻画
例题:
题意:
袋子里有 \(w\) 只白鼠和 \(b\) 只黑鼠 ,\(A\) 和 \(B\) 轮流从袋子里抓,谁先抓到白色谁就赢。\(A\) 每次随机抓一只,\(B\) 每次随机抓完一只之后会有另一只随机老鼠跑出来。如果两个人都没有抓到白色则 \(B\) 赢。\(A\) 先抓,问 \(A\) 赢的概率。
分析:
我们设 \(dp[i][j]\) 表示有 \(i\) 白 \(j\) 黑时 \(A\) 的胜率,然后进行分类讨论:
- \(A\) 白,此时直接赢
- \(A\) 黑,\(B\) 出白,此时 \(B\) 必赢,所以无法转移,跳过
- \(A\) 黑,\(B\) 黑,跑白,此时从 \(dp[i-1][j-2]\) 转移
- \(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\) 肯定输。
题意:
有 \(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;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9