1. 程式人生 > >Bag of mice【概率DP】

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;
}