HDU 3625 Examining the Rooms【第一類斯特靈數】
阿新 • • 發佈:2018-08-13
long 方法 fff void 但是 min art ron get
<題目鏈接>
<轉載於 >>> >
題目大意:
有n個鎖著的房間和對應n扇門的n把鑰匙,每個房間內有一把鑰匙。你可以破壞一扇門,取出其中的鑰匙,然後用取出鑰匙打開另一扇門(如果取出的鑰匙能打開房門則接著打開,取出其中鑰匙,如此往復,若打不開則繼續破壞一扇門)。最多可以破壞k(k<=n)扇門,但是編號為1的門只能用鑰匙打開。求能打開所有門(被破壞或是被鑰匙打開)的概率。
解題分析:
鑰匙和門的關系是成環狀的,打開一個門之後,該環內的所有房間都可以進入,怎麽說呢,就拿Hint裏的#6來舉例,Room1 Room2 Room3是在一個環當中的,假設我破壞了Room3,那麽我取出Room3內的鑰匙Key2就可以打開Room2,而Room2裏有鑰匙Key1,那我們又可以打開Room1。
因此,該題就轉化成了求N個房間形成1~K個環有多少種可能,然後除以總的分配方案數即為題目要我們求的概率。
首先,總的分配方案數是比較好求的,N的全排列N!種,因為N<=20,有可能超int型範圍,所以__int64或long long是必不可少的
其次就是求N個房間成i個環的種類數了,而第一類斯特林數S(N,K)=S(N-1,K-1)+(N-1)*S(N-1,k)恰恰就是求N個元素形成K個非空循環排列的方法數
剩下的就是枚舉形成的環,但是要排除掉編號為1的房間獨立成環的可能
S(N,M)-S(N-1,M-1),表示N個元素形成M個環,減去1獨自成環,即剩下的N-1個元素形成M-1個環,算得的結果便是所求值
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define eps 1e-7 #define LL long long using namespace std; LL fac[21] = { 1 }; LL stir1[21][21]; void INIT() { for (int i = 1; i<21; i++) fac[i] = fac[i - 1] * i; //計算階乘 for (inti = 1; i <= 20; i++) //計算stir數組,表示讓n個物品形成m個環的方案數 { stir1[i][0] = 0; stir1[i][i] = 1; for (int j = 1; j<i; j++) stir1[i][j] = stir1[i - 1][j - 1] + (i - 1)*stir1[i - 1][j]; } } int main() { INIT(); int t, n, k; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &k); if (n == 1 || k == 0) { printf("0.0000\n"); continue; } LL sum = 0; for (int i = 1; i <= k; i++) sum += stir1[n][i] - stir1[n - 1][i - 1]; //減去第一個門獨立成環的情況 printf("%.4f\n", (double)sum / fac[n]); } return 0; }
2018-08-12
HDU 3625 Examining the Rooms【第一類斯特靈數】