Examining the Rooms

来源:互联网 发布:龙少站群软件下载 编辑:程序博客网 时间:2024/05/13 03:45

出处http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove

题目:给出N个房间,每个房间的钥匙随机放在某个房间内,概率相同。有K次炸门的机会,求能进入所有房间的可能性为多大。

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

钥匙与门的对应关系呈现出环。打开一个门之后,环内的所有房间都可以进入。也就是说N个房间形成1--K个环的可能有多大。N个房间N个钥匙的总数为N!。

之后是求N个房间形成i个环的总数。

题目还有个特殊要求,不能破1号的门。

也就是说1号不能独立成环,否则就失败。

第一类斯特林数S(P,K)=(P-1)*S(P-1,K)+S(P-1,K-1)表示的正是N个元素形个K个非空循环排列的方法数。

枚举形成的环,但是要除掉1号独立成环的可能。

S(N,M)-S(N-1,M-1),N个元素形成 M个环,减去除了1之外的N-1个元素形成M-1个环,也就是1独立成环。

[cpp] view plain copy
print?
  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<cstring>  
  4. #include<cmath>  
  5. #define eps 1e-7  
  6. #define LL long long  
  7. using namespace std;  
  8. LL fac[21]={1};  
  9. LL stir1[21][21];  
  10. int main(){  
  11.     for(int i=1;i<21;i++)  
  12.         fac[i]=fac[i-1]*i;  
  13.     for(int i=1;i<=20;i++){  
  14.         stir1[i][0]=0;  
  15.         stir1[i][i]=1;  
  16.        for(int j=1;j<i;j++)  
  17.            stir1[i][j]=stir1[i-1][j-1]+(i-1)*stir1[i-1][j];  
  18.     }  
  19.     int t,n,k;  
  20.     scanf("%d",&t);  
  21.     while(t--){  
  22.         scanf("%d%d",&n,&k);  
  23.         if(n==1||k==0){  
  24.             printf("0.0000\n");  
  25.             continue;  
  26.         }  
  27.         LL sum=0;  
  28.         for(int i=1;i<=k;i++)  
  29.             sum+=stir1[n][i]-stir1[n-1][i-1];  
  30.         printf("%.4f\n",(double)sum/fac[n]);  
  31.     }  
  32.     return 0;  
  33.   
  34. }  
0 0