zoj3822 期望dp
每天在一个n*m的棋盘上放棋子,问使得每一行,每一列都有棋子的期望天数
dp[n][m][k] 表示用k个棋子占据了n行,m列,距离目标状态还需要的期望天数
那么dp[n][m][k] = p1 * dp[n][m][k+1] + p2*dp[n+1][m][k+1] + p3*dp[n][m+1][k+1] + p4*dp[n+1][m+1][k+1] + 1
设s= n*m-k, 即剩下多少个地方可以放棋子
p1 = (i*j-k)/s, p1表示放置一棵棋子后,不增加行也不增加列的概率
p2 = (n-i)*j/s, p2表示放置一棵棋子后,只增加行的概率
p3 = (m-j)*i/s, 只增加列的概率
p4 = (n-j)*(m-j)/s , 即增加行又增加列的概率
模拟比赛的时候,第三维开小了,只报wa,不报re,这样的情况,发生好多次了
1 #pragma warning(disable:4996) 2 #pragma comment(linker, "/STACK:1024000000,1024000000") 3 #include <iostream> 4 #include <stdio.h> 5 #include <string.h> 6 #include <math.h> 7 #include <algorithm> 8 #include <vector> 9 #include <stack> 10 #include <map> 11 #include <set> 12 #include <string> 13 #include <functional> 14 using namespace std; 15 16 /* 17 */ 18 double dp[55][55][2600]; 19 int main() 20 { 21 int N, M, t; 22 scanf("%d", &t); 23 while (t--) 24 { 25 scanf("%d%d", &N, &M); 26 if (N == 1 || M == 1) 27 { 28 printf("%.9lf\n", max(N, M)*1.0); 29 continue; 30 } 31 memset(dp, 0, sizeof(dp)); 32 for (int i = N;i >= 0; --i) 33 { 34 for (int j = M;j >= 0; --j) 35 { 36 if (i == N && j == M) continue; 37 for (int k = i*j;k >= max(i, j); --k) 38 { 39 double s = N*M - k; 40 dp[i][j][k] = (i*j-k)*1.0/s *dp[i][j][k+1]+(N - i)*j*1.0 / s *dp[i + 1][j][k + 1] + (M - j)*i*1.0 / s*dp[i][j + 1][k + 1] + (N - i)*(M - j)*1.0 / s*dp[i + 1][j + 1][k + 1] + 1; 41 //printf("%d %d %d \n", i, j, k); 42 } 43 44 } 45 } 46 47 printf("%.9lf\n", dp[0][0][0]); 48 } 49 return 0; 50 }