Bag of mice【概率DP】

概率DP与期望DP不同,这个是正序的,接下来上一下我的思路,先上题:

Alice和Bob正在玩一个游戏:

一个袋子里一开始装着w个白球和b个黑球。Alice和Bob轮流随机抽出一个球(Alice先手)。如果抽出的球是白色的,则抽出这个球的人获胜。每当一个球被Bob取出后,会有另一个球滚出来(不算任何人抽的)。但Alice取出时很小心,不会让球滚出来。每个人抽球、和自动滚出来的球都是等概率的。那么Alice获胜率是多少呢?

如果最后袋子里没有球了,并且没有人拿到白球,那么Bob获胜。

Input

两个数w,b含义如上。w,b<=1000

Output

Alice获胜的概率,保留至少10位小数。绝对误差或相对误差不超过1e-9时被认为正确。

Sample Input

Input 1: 

1 3

Input 2:

5 5

Sample Output

Output 1:

0.500000000

Output 2:

0.658730159

在第一个样例中,Alice第一次就取得白球并获胜的概率是1/4.。Bob第一次取到黑球的概率是3/4*2/3=1/2. 之后剩下一白一黑两个球; 一个滚出来,另一个被Alice在他的第二轮取到.如果Alice的球是白的,他获胜(1/2*1/2=1/4),否则没有人拿到白球,根据规则Bob获胜.

 

思路

  一开始开了个一维DP,硬是给弄不出来,后来想了想,DP有被称为状态转移方程,那么我枚举了一下Alice赢的时候的状态,不就是直接抓取白球,或者前两次她和Bob均抓了黑球(此间情况还会多出一种掉的球是黑是白的情况)——所以一共三种情况。那么一维DP想必是开不下了,于是我建了个二维的DP,dp[i][j],i表示白球的此时数量,j表示黑球的此时数量。

  那么此时的DP方程该怎么去列写?知道概率DP是正序的,那么就由已知来往上推未知,所以有状态转移方程:

状态转移方程

  • 初始一次性就抓到白球dp[i][j]=(i/(i+j));
  • 前两次都抓到了黑球,掉了白球:if(j>=2) dp[i][j]+=(j/(i+j))*((j-1)/(i+j-1))*(i/(i+j-2))*dp[i-1][j-2];
  • 前两次都抓到了黑球,掉了黑球:if(j>=3) dp[i][j]+=(j/(i+j))*((j-1)/(i+j-1))*((j-2)/(i+j-2))*dp[i][j-3];
  • 细节上,为了精度,我们令i、j转换成double类型。

 

完整代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=1005;
int W, B;
double dp[maxN][maxN];      //i个白球、j个黑球,且此时到了Alice拿球
int main()
{
    while(scanf("%d%d", &W, &B)!=EOF)
    {
        memset(dp, 0, sizeof(dp));
        dp[1][0]=1.;
        for(int i=1; i<=W; i++)
        {
            for(int j=0; j<=B; j++)
            {
                double ii=i, jj=j;
                dp[i][j]=ii/(ii+jj);       //Alice抓到白球
                if(j>=3) dp[i][j]+=(jj/(ii+jj)) * ((jj-1)/(ii+jj-1)) * ((jj-2)/(ii+jj-2)) * dp[i][j-3];
                if(j>=2) dp[i][j]+=(jj/(ii+jj)) * ((jj-1)/(ii+jj-1)) * ((ii)/(ii+jj-2)) * dp[i-1][j-2];
            }
        }
        printf("%.10lf\n", dp[W][B]);
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值