我写的比较搓,是用来自己参考的,各位大佬们
我是从这位巨巨的博客上看到思路的
真的对我理解dp很有帮助
巨巨的传送门
题目大意(copy的 ^)
原来袋子里有w只白鼠和b只黑鼠
龙和王妃轮流从袋子里抓老鼠。谁先抓到白色老鼠谁就赢。
王妃每次只抓一只老鼠,但是龙每次抓完一只老鼠之后会有一只老鼠跑出来。
每次抓老鼠和跑出来的老鼠都是随机的。
如果两个人都没有抓到白色老鼠则龙赢。王妃先抓。
问王妃赢的概率。
这题状态很好找,就是dp[i][j]为白老鼠i个,黑老鼠j个王妃赢得概率
然后就是怎么转移
首先我们考虑公主一上来就拿到白老鼠的情况就是dp[i][j] += i/(i+j)
然后,考虑转移的情况
就是公主抓了一个黑的,龙抓了一个黑的,跑了一个黑的 即 dp[i][j] += j/(i+j) * j-1/(i+j-1) * j-2/(i+j-2) * dp[i][j-3]
还有就是公主抓了一个黑的,龙抓了一个黑的,跑了一个白的 即dp[i][j] += j/(i+j) * j-1/(i+j-1) * i/(i+j-2) * dp[i-1][j-2]
还有一种情况,就是公主抓了一只黑老鼠,龙抓了白的,这样公主输了,就不能转移了
边界很简单,dp[i][0] = 1,dp[0][j] = 0;
我一开始不是很能理解转移的那两种情况,因为我认为之前的那个状态不是已经公主赢了吗,为什么还能转移,其实是我理解错了,dp[i][j]是对应这个状态能赢的概率,不是我们所求的概率,所以我们还需要去转移,但是思路上还是比较难理解。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define LL long long
using namespace std;
double dp[1010][1010];
int main()
{
int w,b;
scanf("%d%d",&w,&b);
memset(dp,0,sizeof(dp));
for(int i=1;i<=w;i++) dp[i][0] = 1;
for(int i=0;i<=b;i++) dp[0][i] = 0;
for(int i=1;i<=w;i++){
for(int j=1;j<=b;j++){
dp[i][j] += (double)i/(i+j);
if(j>=3){
dp[i][j] += (double)j/(i+j) * ((double)(j-1)/(i+j-1)) * ((double)(j-2)/(i+j-2)) * dp[i][j-3];
}
if(j>=2){
dp[i][j] += (double)j/(i+j) * (double)(j-1)/(i+j-1) * ((double)i/(i+j-2)) * dp[i-1][j-2];
}
}
}
printf("%.9lf\n",dp[w][b]);
return 0;
}
加油