H - Collecting Bugs POJ-2096
H - Collecting Bugs POJ-2096
期望 dp
题意
根据题意可以将原题意转换成:
有个 \(n * s\) 的矩阵,每次会随机选取一个格子填上颜色,问每行每列都填上颜色的期望次数。
思路
dp,显然是期望 dp,那么设 \(dp_{i,j}\) 为已经有 \(i\) 行 \(j\) 列填上颜色,到目标还需的次数的期望,那么每次可以选的就有四种情况:
- \(dp_{i,j}\) 什么事也没发生,我选的格子的行列都已经被选过了,概率:\(\frac{ij}{ns} = a\)
- \(dp_{i+1,j}\) 选的格子列已经被选过了,但行未被选过,概率:\(\frac{(n - i)j}{ns} = b\)
- \(dp_{i,j + 1}\) 选的格子列已经被选过了,但行未被选过,概率:\(\frac{i(s - j)}{ns} = c\)
- \(dp_{i + 1,j + 1}\) 选的格子列已经被选过了,但行未被选过,概率:\(\frac{(n - i)(s - j)}{ns} = d\)
那么 \(dp_{i,j}\) 的转移式就是:\(dp_{i,j} = 1 + a \times dp_{i,j} + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}\)
然后我们会发现式子出现了与 \(x=x\) 类似的情况,所以移项得:
\(dp_{i,j} = 1 + a \times dp_{i,j} + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}\)
\(dp_{i,j} - a * dp_{i,j} = 1 + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}\)
\((1 - a) * dp_{i,j} = 1 + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}\)
\(dp_{i,j} = \frac{1 + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}}{1-a}\)
我们发现,现在的这个式子就很正常了,那么最终的转移式就是:\(dp_{i,j} = \frac{1 + b \times dp_{i+1,j} + c \times dp_{i,j+1} + d \times dp_{i+1,j+1}}{1-a}\)
对于这种期望 dp 可以倒着做,所以初始状态为: \(dp_{n,s}=0\),目标为:\(dp_{0,0}\)
code
点击查看代码
#include <iostream>
#include <iomanip>
using namespace std;
const int MaxN = 1010;
int n, s;
double dp[MaxN][MaxN];
int main() {
cin >> n >> s;
for (int i = n; i >= 0; i--) {
for (int j = s; j >= 0; j--) {
if (i == n && j == s) {
continue;
}
double a = 1.0 * i * j / (n * s), b = 1.0 * (n - i) * j / (n * s), c = 1.0 * i * (s - j) / (n * s), d = 1.0 * (n - i) * (s - j) / (n * s);
a != 1 && (dp[i][j] = 1.0 * (b * dp[i + 1][j] + c * dp[i][j + 1] + d * dp[i + 1][j + 1] + 1) / (1.0 - a));
}
}
cout << fixed << setprecision(4) << dp[0][0] << endl;
return 0;
}