• 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
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    Go part 7 反射,反射类型对象,反射值对象
    activemq BytesMessage || TextMessage
    Go part 6 接口,接口排序,接口嵌套组合,接口与类型转换,接口断言
    mysql 查询表的字段名称,字段类型
    冒泡(bubblesort)、选择排序、插入排序、快速排序
    用 python 写一个模拟玩家移动的示例
    day 14(作业)
    day 13
    day 12
    day 11
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11318807.html
Copyright © 2020-2023  润新知