• ZOJ 3822(求期望)


    Domination

    Time Limit: 8 Seconds      Memory Limit: 131072 KB      Special Judge

    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 <= NM <= 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
    

    Author: JIANG, Kai
    Source: The 2014 ACM-ICPC Asia Mudanjiang Regional Contest

    做了这么多概率dp,结果这道还是没做出来,心情已经不能用郁闷二字来形容了。。。

    一、直接求期望

    首先是状态的问题,一直在用二维,其实在算概率的时候就应该意识到二维的概率好难算,数据又是50的,很明显要用三维啊!真是笨死了!

    dp[i][j][k]代表走了k步,已经有i行,j列安放了棋子。

    接下来就是算概率的问题

    很明显有四种可转移状态:

    1、dp[i][j][k+1]表示走完k+1步,仍是有i行,j列安放了棋子。即安放的第k+1个棋子在i,j所占据的区域,概率为 (i * j - k) / (n * m - k);

    2、dp[i][j+1][k+1]表示走完k+1步,有i行,j + 1列安放了棋子。即安放的第k+1个棋子在i行中但不在j列,概率为 i * (m - j) / (n * m - k);

    3、dp[i+1][j][k+1]表示走完k+1步,有i + 1行,j列安放了棋子。即安放的第k+1个棋子在j列中但不在i行,概率为 (n - i) * j / (n * m - k);

    4、dp[i+1][j+1][k+1]表示走完k+1步,有i + 1行,j + 1列安放了棋子。即安放的第k+1个棋子既不在j列中也不在i行,概率为 (n - i) * (m - j) / (n * m - k);

    然后是初始化问题

    当i == n && j == m时候,dp[i][j][k] = 0;

    无意义的状态全部初始为零,没有影响。

    #include <cstdio>
    #include <iostream>
    #include <sstream>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <string>
    #include <vector>
    #include <map>
    #include <set>
    #include <queue>
    #include <stack>
    #include <algorithm>
    using namespace std;
    #define ll long long
    #define _cle(m, a) memset(m, a, sizeof(m))
    #define repu(i, a, b) for(int i = a; i < b; i++)
    #define repd(i, a, b) for(int i = b; i >= a; i--)
    #define sfi(n) scanf("%d", &n)
    #define sfl(n) scanf("%lld", &n)
    #define pfi(n) printf("%d
    ", n)
    #define pfl(n) printf("%lld
    ", n)
    #define MAXN 55
    double dp[MAXN][MAXN][MAXN * MAXN];
    
    
    int main()
    {
        int T;
        sfi(T);
        while(T--)
        {
            int n, m;
            sfi(n), sfi(m);
            _cle(dp, 0);
            for(int i = n; i >= 0; i--)
                for(int j = m; j >= 0; j--)
                    for(int k = i * j; k >= max(i, j); k--)
                    {
                        if(n == i && j == m) continue;
                        dp[i][j][k] += (dp[i][j][k + 1] + 1.0) * 1.0 * (i * j - k);
                        dp[i][j][k] += (dp[i][j + 1][k + 1] + 1.0) * 1.0 * (i * (m - j));
                        dp[i][j][k] += (dp[i + 1][j][k + 1] + 1.0) * 1.0 * (j * (n - i));
                        dp[i][j][k] += (dp[i + 1][j + 1][k + 1] + 1.0) * 1.0 * ((n - i) * (m - j));
                        dp[i][j][k] = dp[i][j][k] / (1.0 * (n * m - k));
                        //printf("%d %d %d : %.12lf
    ", i, j, k, dp[i][j][k]);
                    }
             printf("%.12lf
    ", dp[0][0][0]);
        }
        return 0;
    }
    View Code

    二、先求概率,再求期望

     dp[i][j][k]表示放k个棋子达到有i行,j列安放了棋子的概率。

    这里有一大误区,就是开始我和我队友都搞错了,结果还以为自己是算的不对,其实是思考错了,就是在算期望是应只考虑真正起作用的棋子,eg:

    2 2

    dp[2][2][3] = 1, dp[2][2][4] = 1;

    其实在放第四颗棋子时就已经必然为两行两列,第四颗棋子已不起作用,放与不放无关痛痒,所以,放第k颗棋子的概率为:

    dp[i][j][k] - dp[i][j][k - 1];

    #include <cstdio>
    #include <iostream>
    #include <sstream>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <string>
    #include <vector>
    #include <map>
    #include <set>
    #include <queue>
    #include <stack>
    #include <algorithm>
    using namespace std;
    #define ll long long
    #define _cle(m, a) memset(m, a, sizeof(m))
    #define repu(i, a, b) for(int i = a; i < b; i++)
    #define repd(i, a, b) for(int i = b; i >= a; i--)
    #define sfi(n) scanf("%d", &n)
    #define sfl(n) scanf("%lld", &n)
    #define pfi(n) printf("%d
    ", n)
    #define pfl(n) printf("%lld
    ", n)
    #define MAXN 55
    double dp[MAXN][MAXN][MAXN * MAXN];
    
    
    int main()
    {
        int T;
        sfi(T);
        while(T--)
        {
            int n, m;
            sfi(n), sfi(m);
            _cle(dp, 0);
            dp[0][0][0] = 1.0;
            repu(i, 1, n + 1)
            repu(j, 1, m + 1)
            repu(k, max(i, j), i * j + 1)
            {
                if(k < 1) continue;
                dp[i][j][k] += dp[i][j][k - 1] * 1.0 * (i * j - k + 1);
                dp[i][j][k] += dp[i - 1][j][k - 1] * 1.0 * ((n - i + 1) * j);
                dp[i][j][k] += dp[i][j - 1][k - 1] * 1.0 * (i * (m - j + 1));
                dp[i][j][k] += dp[i - 1][j - 1][k - 1] * 1.0 * ((n - i + 1) * (m - j + 1));
                dp[i][j][k] /= (1.0 * (n * m - k + 1));
                //printf("%d %d %d : %.12lf
    ", i, j, k, dp[i][j][k]);
            }
            double ans = 0.0;
            repu(i, max(n, m), n * m + 1)
             ans += (dp[n][m][i] - dp[n][m][i - 1]) * 1.0 * i;
            printf("%.12lf
    ", ans);
            //double f = ans * 3.0;
    
        }
        return 0;
    }
    View Code

     

  • 相关阅读:
    Golang 学习之路
    Kubernetes 资源对象之DaemonSet
    Spring Cloud服务注册中心交付至kubernetes
    自动化运维之Ansible入门
    MySQL 高可用之主从复制
    Kubernetes 强大的namespace
    SaltStack RESTful API操作
    Kubernetes 服务自动发现CoreDNS
    2个月……
    一次游玩与这两周的一些感想
  • 原文地址:https://www.cnblogs.com/sunus/p/4693806.html
Copyright © 2020-2023  润新知