-----概率DP ZOJ 3822- Domination

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 by the chess pieces. That means there is at least one chess piece in every row. Also, there is at least one chess piece in every column.

“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 T indicating 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
題意:
給你一個N*M的棋盤,每天都會隨機在棋盤上放一顆棋子,要求至少每行每列都要有一顆棋子,求滿足條件下的天數的期望
解題思路
概率DP
dp[i][j][k]表示,已經放了i顆棋子,覆蓋了 j行k列的概率
然後推狀態方程
這裏寫圖片描述
由該圖可知,在滿足題目要求的條件之前,不論是哪個狀態下都能分成如上四個區域,狀態方程如下:
當前的概率=前一步的概率*當前的概率
區域一:放在舊的行和舊的列之中,只有棋子數增加,行數和列數保持不變
dp[i+1][j][k]+=dp[i][j][k]*(j*k-i)/(n*m-i)
區域二:新的行和舊的列,棋子數增加,行數增加,列數保持不變
dp[i+1][j+1][k]+=dp[i][j][k]*((n-j)*k)/(n*m-i)
區域三:舊的行和新的列,棋子數增加,行數保持不變,列數增加
dp[i+1][j][k+1]+=dp[i][j][k](j(m-k))/(n*m-i)
區域四:新的行和新的列,旗子數增加,行數增加,數數增加
dp[i+1][j+1][k+1]+=dp[i][j][k]((n-j)(m-k))/(n*m-i)
!!還要注意每個狀態方程的條件

#include <iostream>
#include <cstring>
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=55;
double dp[maxn*maxn][maxn][maxn];
int n,m;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));
        dp[1][1][1]=1;
        for(int i=1; i<n*m; i++)
            for(int j=1; j<=n; j++)
                for(int k=1; k<=m; k++)
                {
                    if(dp[i][j][k]==0||j==n&&k==m) continue;
                    if(j*k>i) dp[i+1][j][k]+=dp[i][j][k]*(j*k-i)/(n*m-i);
                    if(j<n) dp[i+1][j+1][k]+=dp[i][j][k]*((n-j)*k)/(n*m-i);
                    if(k<m) dp[i+1][j][k+1]+=dp[i][j][k]*(j*(m-k))/(n*m-i);
                    if(j<n&&k<m) dp[i+1][j+1][k+1]+=dp[i][j][k]*((n-j)*(m-k))/(n*m-i);
                }
        double ans=0;
        for(int i=1; i<=n*m; i++)
            ans+=i*dp[i][n][m];
            printf("%.12lf\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章