Codeforces Round 105 (Div. 2) - D. Bag of mice DP 或 记忆化搜索 求概率

D. Bag of mice

题意

龙和公主玩一个游戏。袋子里共有 w 只白老鼠和 b 只黑老鼠,它俩轮流从袋子里捉老鼠,公主先来,先抓到白老鼠的胜利。当龙抓完老鼠后,将会惊动鼠群,会有一只老鼠逃出袋子,每只老鼠逃出的概率相同;公主手脚灵活,不会惊动鼠群。问你最后公主赢的概率?
(没有老鼠算龙赢;逃出的老鼠不会再回去,也不算谁抓出的;每只老鼠抓出或者逃出的概率相等)

思路

可利用 DP 或者记忆化搜索求解本问题,实际上这两个方法等价。
\(w = 0\) 时必输
当 $w \ne 0 $ 但 $b = 0 $ 时必赢
剩下的情况,先考虑一个问题:赢的局面是怎么构成的?
在第一轮赢得概率:$P = \frac{w}{w + b} $
第一轮不赢,那么赢得概率分为两种:

  • 老鼠黑黑,跑了白,问题转化为 $f[w - 1][b - 2] $,概率即为再乘上这么选的概率
  • 老鼠黑黑,跑了黑,问题转化为 $f[w][b - 3] $,概率即为再乘上这么选的概率

最后可得递推公式:
$f[w][b] = \frac{w}{w + b} + \frac{b}{w + b} \times \frac{b - 1}{w + b - 1} \times \frac{w}{w + b - 2} \times f[w - 1][b - 2] + \frac{b}{w + b} \times \frac{b - 1}{w + b - 1} \times \frac{b - 2}{w + b - 2} \times f[w][b - 3] $
注意边界情况!!!而且有那么多个球才可以递推
所以这题可以利用记忆化搜索或者 DP 求解

代码

  • 记忆化搜索
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
这一发记忆化搜索
*/
const int maxm = 1e3 + 5, inf = 0x3f3f3f3f, mod = 998244353;
double dp[maxm][maxm];

double dfs(int n, int m){
	if(n <= 0 || m < 0) return 0;       //attention!
	if(m == 0) return 1;
	if(dp[n][m] != 0) return dp[n][m];
	dp[n][m] = 1.0 * n / (n + m);
	if(n + m >= 3){
		dp[n][m] += dfs(n - 1, m - 2) * m * (m - 1) * n / (n + m) / (n + m - 1) / (n + m - 2)
			+   dfs(n, m - 3) * m * (m - 1) * (m - 2) / (n + m) / (n + m - 1) / (n + m - 2);
	}
	return dp[n][m];
}

void solve(){
	int w, b;
	cin >> w >> b;
	cout << fixed << setprecision(9) << dfs(w, b) << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}
  • DP
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
 
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
DP
*/
const int maxm = 1e3 + 5, inf = 0x3f3f3f3f, mod = 998244353;
double dp[maxm][maxm];

void solve(){
	for(int i = 0; i < maxm; ++ i){
		dp[i][0] = 1;
		dp[0][i] = 0;
	}
	int w, b;
	cin >> w >> b;
	for(int i = 1; i <= w; ++ i){
		for(int j = 1; j <= b; ++ j){
			dp[i][j] = 1.0 * i / (i + j);
			if(i + j >= 3){
				if(j >= 2)
					dp[i][j] += dp[i - 1][j - 2] * j * (j - 1) * i / (i + j) / (i + j - 1) / (i + j - 2);
				if(j >= 3)
					dp[i][j] += dp[i][j - 3] * j * (j - 1) * (j - 2) / (i + j) / (i + j - 1) / (i + j - 2);
			}
		}
	}
	cout << fixed << setprecision(9) << dp[w][b] << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}
posted on 2023-07-29 22:20  Qiansui  阅读(7)  评论(0编辑  收藏  举报