ZOJ 3822 Domination(概率dp)

一个n行m列的棋盘,每天可以放一个棋子,问要使得棋盘的每行每列都至少有一个棋子 需要的放棋子天数的期望。

dp[i][j][k]表示用了k天棋子共能占领棋盘的i行j列的概率。

他的放置策略是,每放一次,就会有四种可能

1)增加一行一列

2)增加一行

3)增加一列

4)不变

所以他放置的概率就可以求出来,每次放下的概率就是当前能放的点除以总的空的点数。

最后统计期望的时候需要统计在第k天刚好符合占满n行m列的概率,就是dp[i][j][k]-dp[i][j][k-1]

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 52;
double dp[maxn][maxn][maxn*maxn];

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int n, m;
        scanf("%d %d", &n, &m);
        int sum = n * m;
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= m; j++)
                for (int k = 0; k <= sum; k++)
                    dp[i][j][k] = 0;
        dp[0][0][0] = 1.0;
        for (int k = 1; k <= sum; k++)
        {
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= m; j++)
                {
                    dp[i][j][k] += dp[i][j][k - 1] * ((i * j - k + 1) * 1.0 / (sum - k + 1));//新添加的位置没有新增加行和列,所以他的概率就是(还剩下多少个符合不增加行和列能填的格子)/总的能填的格子
                    dp[i][j][k] += dp[i - 1][j][k - 1] * ((n - i + 1) * j * 1.0 / (sum - k + 1));//同理增加行不增加列
                    dp[i][j][k] += dp[i][j - 1][k - 1] * (i * (m - j + 1) * 1.0 / (sum - k + 1));//增加列不增加行
                    dp[i][j][k] += dp[i - 1][j - 1][k - 1] * ((n - i + 1) * (m - j + 1) * 1.0 / (sum - k + 1));//增加行和列
                }
            }
        }
        double ans = 0;
        for (int k = 1; k <= sum; k++)
            ans += (dp[n][m][k] - dp[n][m][k - 1]) * k;//第k天刚好填满n和m所以就是dp[n][m][k] - dp[n][m][k - 1]
        printf("%.10f\n", ans);

    }

    return 0;
}

 

posted @ 2015-10-08 11:12  Howe_Young  阅读(209)  评论(0编辑  收藏  举报