Bag of mice【概率DP】
阿新 • • 發佈:2018-12-12
概率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贏的時候的狀態,不就是直接抓取白球
那麼此時的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;
}