码迷,mamicode.com
首页 > 其他好文 > 详细

HDU3265 Examining the Rooms【stirling数】

时间:2015-08-17 10:12:45      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3625


题目大意:

有N个房间,每个房间的要是随机放在某个房间内,概率相同。有K次炸门的机会。

求能打开所有房间门,进入所有房间的概率有多大。


解题思路:

门和钥匙的对应关系出现环。打开一个门后,环内的门都可以打开。也就意味着:

N个房间的钥匙与门形成1~K个环的概率有多大。

也就是求N个元素,构成K个以内的环,且1不成自环的概率。

N个元素形成K个环的方法数是第一类stirling数 S(N,K)。

N个元素形成K个环,且1成自环的方法数是S(N-1,K-1)。

则N个元素形成K个环,且1不成自环的方法数是S(N,K) - S(N-1,K-1)。

要是随机放的总的方法数为N!。

则概率P(N,K)为( S(N,K) - S(N-1,K-1) + S(N,K-1) - S(N-1,K-2) + … + 

S(N,1) - S(N,0) ) / N!


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;

LL F[25],Stirling[25][25];

void Solve()
{
    F[0] = 1;
    for(int i = 1; i <= 20; ++i)    //阶乘数组
        F[i] = i*F[i-1];

    for(int i = 1; i <= 20; ++i)    //算出第一类stirling数
        Stirling[i][0] = 0;
    Stirling[1][1] = 1;
    for(int i = 1; i <= 20; ++i)
    {
        for(int j = 1; j <= i; ++j)
        {
            if(i == j)
                Stirling[i][j] = 1;
            else
                Stirling[i][j] = Stirling[i-1][j-1] + (i-1)*Stirling[i-1][j];
        }
    }

    for(int i = 1; i <= 20; ++i)    //取绝对值
    {
        for(int j = 1; j <= 20; ++j)
        {
            Stirling[i][j] = abs(Stirling[i][j]);
        }
    }
}

int main()
{
    Solve();
    int T,N,K;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&N,&K);
        LL sum = 0;
        for(int i = 1; i <= K; ++i)
            sum += Stirling[N][i] - Stirling[N-1][i-1];
        printf("%.4f\n",(double)sum / (double)F[N]);    //.4lf输出不了正确结果
    }

    return 0;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU3265 Examining the Rooms【stirling数】

标签:

原文地址:http://blog.csdn.net/lianai911/article/details/47720379

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!