1. 程式人生 > >HDU 3625 Examining the Rooms【第一類斯特靈數】

HDU 3625 Examining the Rooms【第一類斯特靈數】

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 (int
i = 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【第一類斯特靈數】