ZOJ 3822 Domination 概率DP 2014年ACM_ICPC亞洲區域賽牡丹江現場賽D題
阿新 • • 發佈:2019-01-30
題目大意:
就是現在有一個N*M的棋盤(1 <= N, M <= 50)每次在上面的空位置隨機選一個放一個棋子, 問使得所有行和所有列上都有棋子放置, 放置的棋子的數目期望
大致思路:
這題同步賽的時候沒感覺, 現在做發現就是一個水題, 當時還是太弱了...
狀態轉移方程見程式碼註釋吧..
程式碼如下:
Result : Accepted Memory : 51276 KB Time : 1750 ms
/* * Author: Gatevin * Created Time: 2014/12/23 20:26:43 * File Name: Sora_Kasugano.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; /* * 用dp[i][j][k]表示對於N*M的棋盤, 已經用k個子佔了i行和j列時到達目標狀態需要的chess piece數量期望 * 那麼顯然dp[N][M][min(N, M)~N*M] = 0, 狀態轉移方程: * dp[i][j][k] = (N - i)*(M - j)/(N*M - k)*(dp[i + 1][j + 1][k + 1] + 1) * + (N - i)*j/(N*M - k)*(dp[i + 1][j][k + 1] + 1) * + i*(M - j)/(N*M - k)*(dp[i][j + 1][k + 1] + 1) * + (i*j - k)/(N*M - k)*(dp[i][j][k + 1] + 1) * 考慮一下邊界條件即可, dp[0][0][0]即為答案 */ /* * 牡丹江那場區域賽在同步賽場外做的時候沒思路, 現在一看的確是個水題..當時還是太弱了 */ double dp[51][51][2510]; int main() { int t; scanf("%d", &t); int N, M; while(t--) { scanf("%d %d", &N, &M); memset(dp, 0, sizeof(dp)); for(int i = N; i >= 0; i--) for(int j = M; j >= 0; j--) { if(i == N && j == M) continue; for(int k = i*j; k >= min(i, j); k--) { dp[i][j][k] = 0; if(i + 1 <= N && j + 1 <= M && (i + 1)*(j + 1) >= k + 1) dp[i][j][k] += (N -i)*(M - j)*1.0/(N*M - k)*(dp[i + 1][j + 1][k + 1] + 1); if(i + 1 <= N && (i + 1)*j >= k + 1) dp[i][j][k] += (N - i)*j*1.0/(N*M - k)*(dp[i + 1][j][k + 1] + 1); if(j + 1 <= M && (j + 1)*i >= k + 1) dp[i][j][k] += i*(M - j)*1.0/(N*M - k)*(dp[i][j + 1][k + 1] + 1); if(i*j >= k + 1) dp[i][j][k] += (i*j - k)*1.0/(N*M - k)*(dp[i][j][k + 1] + 1); } } printf("%.8f\n", dp[0][0][0]); } return 0; }