3822 概率dp
Edward is the headmaster of Marjar University. He is enthusiastic about chess and often plays chess with his friends. What's more, he bought a large decorative chessboard with N rows and M columns.
Every day after work, Edward will place a chess piece on a random empty cell. A few days later, he found the chessboard was dominated
"That's interesting!" Edward said. He wants to know the expectation number of days to make an empty chessboard of N × M dominated. Please write a program to help him.
Input
There are multiple test cases. The first line of input contains an integer Tindicating the number of test cases. For each test case:
There are only two integers N and M (1 <= N, M <= 50).
Output
For each test case, output the expectation number of days.
Any solution with a relative or absolute error of at most 10-8 will be accepted.
Sample Input
2 1 3 2 2
Sample Output
3.000000000000 2.666666666667
題解:要求次數的期望 我們先明確 期望 = 次數 * 該次數對應的概率 那明確這一點 動態轉移方程就很容易寫了
dp[k][i][j] 表示 放了k個 已經有i行 j列 滿足條件然後就可以分4種情況了 在放一個 加一行,加一列,都不變,都加1 詳見程式碼
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=51;
int n,m;
double dp[N*N][N][N];
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int k=0;k<=n*m;k++)
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
{
if(i==n&&j==m) continue;//當然 已經滿足條件後就不要繼續求了
if(i*j>=k) dp[k+1][i][j]+=dp[k][i][j]*(i*j-k)/(n*m-k);
if(i<n) dp[k+1][i+1][j]+=dp[k][i][j]*(n-i)*j/(n*m-k);
if(j<m) dp[k+1][i][j+1]+=dp[k][i][j]*(m-j)*i/(n*m-k);
if(i<n&&j<m) dp[k+1][i+1][j+1]+=dp[k][i][j]*(n-i)*(m-j)/(n*m-k);
}
double ans=0;
for(int i=max(n,m);i<=n*m;i++)ans+=dp[i][n][m]*i;
printf("%.12f\n",ans);
}
return 0;
}