Collecting Bugs
大致题意:
n个bug类型,m个子系统.每天出现一个bug,bug出现的类型的子系统位置都是等概率的
求所有子系统出现bug且所有bug类型都出现过的期望天数
解题思路:
概率dp求期望一般是逆推
状态表示:f[i][j]表示已经找到i中bug,j个子系统的bug的期望天数
初始化f[n][m]=0,f[0][0]为答案
分析: f[i][j]有四种转移状态
------- f[i][j] 发现一个bug,该类型存在,出现在已有系统 概率p1=(i/n)/(j*m)
------- f[i][j+1] 发现一个bug,该类型存在,没有出现在已有系统 概率p2=(i/n)/(1-j*m)
------- f[i+1][j] 发现一个bug,该类型不存在,出现在已有系统 概率p3=(1-i/n)/(j*m)
------- f[i+1][j+1] 发现一个bug,该类型不存在,没有出现在已有系统 概率p4=(1-i/n)/(1-j*m)
整理得出转移方程 f[i][j]=1+p1*f[i][j]+p2*f[i][j+1]+p3*f[i+1][j]+p4*f[i+1][j+1]
将f[i][j]移项相消,得 f[i][j]=(1+p2*f[i][j+1]+p3*f[i+1][j]+p4*f[i+1][j+1] )/(1-p1)
AC代码:
#include<iostream>
#include<cstdio>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define debug(a) cout << #a << " = " << a << endl;
using namespace std;
typedef long long ll;
const int N = 1010;
int n, m; //bug类型 子系统
double f[N][N]; //已经找到i中bug,j个子系统的bug的期望天数
int main(void)
{
cin >> n >> m;
f[n][m] = 0;
for (int i = n; i >= 0; --i)
for (int j = m; j >= 0; --j) {
if (i == n && j == m)continue;
f[i][j] += (n * m + i * (m - j) * f[i][j + 1] + (n - i) * j * f[i + 1][j] + (n - i) * (m - j) * f[i + 1][j + 1]) / (n * m - i * j);
}
printf("%.4f\n", f[0][0]);
return 0;
}