集合的劃分——遞歸與函數自調用算法

題目描述 Description
設S是一個具備n個元素的集合,S={a1,a2,……,an},現將S劃分紅k個知足下列條件的子集合S1,S2,……,Sk ,且知足:
則稱S1,S2,……,Sk是集合S的一個劃分。它至關於把S集合中的n個元素a1 ,a2,……,an 放入k個(0<k≤n<30=無標號的盒子中,使得沒有一個盒子爲空。請你肯定n個元素a1 ,a2 ,……,an 放入k個無標號盒子中去的劃分數S(n,k)
輸入輸出格式 Input/output
輸入格式:
一個正整數K。
輸出格式:
一個正整數N。
 輸入輸出樣例 Sample input/output
樣例測試點#1
輸入樣例:
23 7
輸出樣例:
4382641999117305
思路:
先舉個例子,設S={1,2,3,4},k=3,不可貴出S有6種不一樣的劃分方案,即劃分數S(4,3)=6,具體方案爲:
{1,2}∪{3}∪{4}  {1,3}∪{2}∪{4}    {1,4}∪{2}∪{3}
{2,3}∪{1}∪{4}  {2,4}∪{1}∪{3}    {3,4}∪{1}∪{2}
考慮通常狀況,對於任意的含有n個元素a1 ,a2,……,an的集合S,放入k個無標號的盒子中去,劃分數爲S(n,k),咱們很難憑直覺和經驗計算劃分數和枚舉劃分的全部方案,必須概括出問題的本質。其實對於任一個元素an,則必然出現如下兩種狀況:
一、{an}是k個子集中的一個,因而咱們只要把a1,a2,……,an-1 劃分爲k-1子集,便解決了本題,這種狀況下的劃分數共有S(n-1,k-1)個;
二、{an}不是k個子集中的一個,則an必與其它的元素構成一個子集。則問題至關於先把a1,a2,……,an-1 劃分紅k個子集,這種狀況下劃分數共有S(n-1,k)個;而後再把元素an加入到k個子集中的任一個中去,共有k種加入方式,這樣對於an的每一種加入方式,均可以使集合劃分爲k個子集,所以根據乘法原理,劃分數共有k * S(n-1,k)個
綜合上述兩種狀況,應用加法原理,得出n個元素的集合{a1,a2,……,an}劃分爲k個子集的劃分數爲如下遞歸公式:S(n,k)=S(n-1,k-1) + k * S(n-1,k) (n>k,k>0)。
下面,咱們來肯定S(n,k)的邊界條件,首先不能把n個元素不放進任何一個集合中去,即k=0時,S(n,k)=0;也不可能在不容許空盒的狀況下把n個元素放進多於n的k個集合中去,即k>n時,S(n,k)=0;再者,把n個元素放進一個集合或把n個元素放進n個集合,方案數顯然都是1,即k=1或k=n時,S(n,k)=1。
所以,咱們能夠得出劃分數S(n,k)的遞歸關係式爲:
S(n,k)=S(n-1,k-1) + k * S(n-1,k)      (n>k,k>0)
S(n,k)=0            (n<k)或(k=0)
S(n,k)=1            (k=1)或(k=n)
代碼以下:
 1 #include <stdio.h>
 2 int jihe(int n,int k)//數據還有可能越界,請用高精度計算
 3 {
 4     if((n<k)||(k==0)) return 0;
 5     else if((k==1)||(k==n)) return 1;
 6     else return jihe(n-1,k-1)+k*jihe(n-1,k);    
 7 }
 8 int main()
 9 {
10     int n,k;
11     scanf("%d%d",&n,&k);
12     printf("%d\n",jihe(n,k)); 
13     return 0;
14 }
相關文章
相關標籤/搜索