H - Collecting Bugs POJ-2096

H - Collecting Bugs POJ-2096

期望 dp

题意

根据题意可以将原题意转换成:
有个 \(n * s\) 的矩阵,每次会随机选取一个格子填上颜色,问每行每列都填上颜色的期望次数。

思路

dp,显然是期望 dp,那么设 \(dp_{i,j}\) 为已经有 \(i\)\(j\) 列填上颜色,到目标还需的次数的期望,那么每次可以选的就有四种情况:

  1. \(dp_{i,j}\) 什么事也没发生,我选的格子的行列都已经被选过了,概率:\(\frac{ij}{ns} = a\)
  2. \(dp_{i+1,j}\) 选的格子列已经被选过了,但行未被选过,概率:\(\frac{(n - i)j}{ns} = b\)
  3. \(dp_{i,j + 1}\) 选的格子列已经被选过了,但行未被选过,概率:\(\frac{i(s - j)}{ns} = c\)
  4. \(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;
}
posted @ 2023-08-02 10:06  yabnto  阅读(15)  评论(0编辑  收藏  举报