1. 程式人生 > >D - Domination ZOJ - 3822[概率dp]

D - Domination ZOJ - 3822[概率dp]

題意:問期望多少天能把一個n*m的棋盤放成每一行每一列都至少有一個棋子的樣子,一天只能放一個。


題解:動態規劃,可以考慮 d p [ i ] [ j ]

[ k ] dp[i][j][k] 為i天放了i行和j列的概率,然後可以通過當前狀態可以轉移到下一天的概率。
如使 i + 1
i+1
天 :

  1. 佔i行和j列
  2. 佔i+1行和j+1列
  3. 佔i行j+1列
  4. 佔i+1行j列

具體轉移見程式碼。


收穫:概率不是平均值,這也是為什麼暴力的結果是2.8。


a c   c

o d e : ac\ code:

/**hqx is the best**/
/*****陣列大小*****/
/**hqx is the best**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug cerr << "*" << endl;
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define pre(i, a, b) for(int i = a; i >= b; i--)
#define met(a, b) memset(a, b, sizeof(a))
const int maxn = 41 + 10;
const int inf = 0x3f3f3f3f;
int T, n, m;

double dp[maxn * maxn][maxn][maxn];

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        met(dp, 0.0);
        dp[1][1][1] = 1.0;
        for(int i = 1; i <= n * m; i++) {
            for(int j = 1; j <= n; j++) {
                for(int k = 1; k <= m; k++) {
                    dp[i + 1][j][k] += dp[i][j][k] * 1.0 * (j * k - i) / (double)(n * m - i);
                    dp[i + 1][j + 1][k] += dp[i][j][k] * 1.0 * ((n - j) * k) / (double)(n * m - i);
                    dp[i + 1][j][k + 1] += dp[i][j][k] * 1.0 * ((m - k) * j) / (double)(n * m - i);
                    dp[i + 1][j + 1][k + 1] += dp[i][j][k] * 1.0 * ((m - k) * (n - j)) / (double)(n * m - i);
                }
            }
        }
        double ans = 0.0;
        for(int i = 1; i <= n * m; i++) {
            ans += 1.0 * (dp[i][n][m] - dp[i - 1][n][m]) * i;
        }
        printf("%.10f\n", ans);
    }
    return 0;
}