• HDU-3625 Examining the Rooms (第一类斯特林数)


    题目链接:HDU-3625 Examining the Rooms

    题意

    有$n$把对应开$n$个房间的钥匙,每把钥匙随机出现在一个房间里,一个房间里有且仅有一把钥匙。我们现在手上没有钥匙,但有$k$次机会可以炸开一个房间,且不能炸1号房间,每次炸开一个房间后,拿到里面的钥匙去开另一个房间,直到不能打开新的房间,再进行炸开房间的操作......给出$n$和$k$,问我们能够打开所有房间的概率。


    思路

    钥匙放在哪个房间是个排列,比如我们用2,3,1,4表示1号房间里放着2号房间的钥匙,2号房间里放着3号房间的钥匙......可以发现这个排列里有两个循环节${2,3,1}$和${4}$,或者称之为两个环,对于每个环我们炸一次就可以打开环上所有的房间,所以成功的情况就是环的个数小于等于$k$并且1号钥匙不在1号房间里。

    把$n$把不同的钥匙排成$i$个循环节的排列的方法数就是第一类斯特林数的内容,我们用$s(n,i)$表示。

    不能炸1号房间也就是排列的1号点不能单独成环。当排列有$i$个环,1号点单独成环的情况就是其余$n-1$个点成$i-1$个环,即$s(n-1,i-1)$。

    所以答案为:
    $$
    frac{sum_{i=1}^k{(s(n,i)-s(n-1,i-1))}}{n!}
    $$
    第一类斯特林数递推式:$s(n,i)=(n-1)s(n-1,i)+s(n-1,i-1)$


    代码实现

    #include <cstdio>
    typedef long long LL;
    const int N = 25;
    LL s[N][N], f[N];
    
    int main() {
        s[0][0] = f[0] = 1;
        for (int i = 1; i < N; i++) {
            f[i] = f[i-1] * i;
            for (int j = 1; j <= i; j++) {
                s[i][j] = s[i-1][j-1] + s[i-1][j] * (i - 1);
            }
        }
        int t;
        scanf("%d", &t);
        while (t--) {
            int n, k;
            LL sum = 0;
            scanf("%d %d", &n, &k);
            for (int i = 1; i <= k; i++) sum += s[n][i] - s[n-1][i-1];
            printf("%.4f
    ", double(sum) / f[n]);
        }
        return 0;
    }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    fetch与xhr的对比
    使用 fetch
    数组的剩余方法
    slice方法与splice方法
    php命名空间使用
    PHP面向对象编程学习之对象基础
    ubuntu下lamp环境配置及将window代码迁移至linux系统
    ThinkPHP中使用ajax接收json数据的方法
    给js文件传递参数
    JavaScript和php常用语法——切割字符串
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11318807.html
Copyright © 2020-2023  润新知