Zoj--3822(概率DP)
2014-10-12 16:06:26
思路:dp[a][b][k]表示用k个棋子使得a × b的棋盘达到要求的概率,递推即可。用的正推(反推没想出来QAQ)
1 /************************************************************************* 2 > File Name: d.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Sun 12 Oct 2014 12:45:12 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <queue> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 #define lp (p << 1) 20 #define rp (p << 1|1) 21 #define getmid(l,r) (l + (r - l) / 2) 22 #define MP(a,b) make_pair(a,b) 23 typedef long long ll; 24 const int INF = 1 << 30; 25 26 int T,N,M,st,top; 27 double ans,t,n,m; 28 double dp[51][51][2501]; 29 30 int main(){ 31 scanf("%d",&T); 32 while(T--){ 33 scanf("%d%d",&N,&M); 34 memset(dp,0,sizeof(dp)); 35 n = N; 36 m = M; 37 t = n * m; 38 ans = 0.0; 39 dp[1][1][1] = 1.0; 40 for(int a = 1; a <= N; ++a){ 41 for(int b = 1; b <= M; ++b){ 42 if(a == N && b == M) 43 continue; 44 st = 1; 45 top = N * M; 46 for(int k = st; k <= top; ++k){ 47 if(a < N) 48 dp[a + 1][b][k + 1] += dp[a][b][k] * (n - a) * b / (t - k); 49 if(b < M) 50 dp[a][b + 1][k + 1] += dp[a][b][k] * (m - b) * a / (t - k); 51 if(a < N && b < M) 52 dp[a + 1][b + 1][k + 1] += dp[a][b][k] * (m - b) * (n - a) / (t - k); 53 if(k < a * b) 54 dp[a][b][k + 1] += dp[a][b][k] * (1.0 * a * b - k) / (t - k); 55 } 56 } 57 } 58 for(int i = 1; i <= N * M; ++i) 59 ans += dp[N][M][i] * i; 60 printf("%.12f\n",ans); 61 } 62 return 0; 63 }