ZOJ 3288 概率dp
阿新 • • 發佈:2022-02-14
題目大意
給定一個\(n \times m\)的棋盤,每天隨機往裡面一個空位置放一個棋子,問期望多少天之後棋盤每一行都有至少一個棋子,每一列至少一個棋子。
\(n,m \leq 50\)
思路
設\(f_{i,j,k}\)表示用\(k\)個棋子覆蓋\(i\)行\(j\)列的概率是多少。
每次轉移只有四種方式:
- 選已經覆蓋但是仍有空缺的位置進行放置,注意已經處理到\(n,m\)的時候沒有此項
- 選一個行未覆蓋過列覆蓋過的位置
- 選一個行覆蓋過列未覆蓋過的位置
- 選一個行列都為覆蓋過的位置
程式碼
#include <bits/stdc++.h> using namespace std; const int N = 60; double f[N][N][N*N]; int main () { int T; cin >> T; while(T --) { int n,m; cin >> n >> m; memset(f,0.0,sizeof f); f[0][0][0] = 1; for(int i = 1;i <= n; i ++) { for(int j = 1;j <= m; j ++) { for(int k = 1;k <= n * m;k ++) { double p1 = f[i][j][k - 1] * (i * j - (k - 1)); double p2 = f[i - 1][j][k - 1] * (n - i + 1) * j; double p3 = f[i][j - 1][k - 1] * i * (m - j + 1); double p4 = f[i - 1][j - 1][k - 1] * (n - i + 1) * (m - j + 1); if(i == n && j == m) { f[i][j][k] = (p2 + p3 + p4) / (n * m - (k - 1)); }else { f[i][j][k] = (p1 + p2 + p3 + p4) / (n * m - (k - 1)); } } } } double ans = 0; for(int i = 1;i <= n * m; i ++ ) { ans += f[n][m][i] * i; } printf("%.10lf\n",ans); } }