問題描述:
n個元素的集合可以劃分為若干個非空子集。例如,當n=4 時,集合可以劃分為15 個不同的非空子集如下:
,,,},
,,},
,,},
,,},
,,},
,,},
,,},
,},,},
,},,},
,},,},
,},}
給定正整數n,計算出n個元素的集合可以劃分為多少個不同的非空子集。
所求的是bell 數 滿足遞推公式 b(n) =
所以這道題實際求第二類stirling數 s(n,m)
解決思想:
1. 若 m == 1 則s(n,m) = 1; ( n >= 0 )
2. 若 m == 0 則s(n,m) = 0; ( n >= 1 )
3. 若 n == m 則s(n,m) = 1;
4 . 若非以上3中情況 則:
(1) 已知前s(n-1,m)的解決方案 , 第n個數可以向分出來的m個非空子集中的每乙個任意新增進去 共有m*s(n-1,m)方法
(2) 前n-1個數已經劃分成 m-1 剩餘第n個數單獨作為乙個非空子集新增進去 共有s(n-1,m-1)種方法
#include using namespace std;
int f( int n , int m )
//bell數
int main()
cout << sum << endl;
return 0;
}
對於遞迴中資料量為n 的時候 一般情況下寫出的遞迴公式裡面一定含有n 或者有其他題目中的引數 例如此題中的m
遞迴最重要的思想: 至頂向下 假設已知前n-1時的解決方案 有了第n-1是的解決方案 才能求第n個 。 要求第n個時 可能有多種情況(每一種情況都能列出乙個遞迴公式) 最後將多種情況的結果相加即最終答案 所謂的終止條件即: 當遞迴回溯到了人腦可以算出的小資料量的時候, "例如" 當n到了1 那麼可以知道n=2時的結果 知道2的結果可求3 繼而遞推到n。
這裡面的回溯和搜尋裡面的回溯雖然名字相同 但是意義略有不同 搜尋裡面的回溯一般是一種不斷去嘗試的過程 例如n皇后問題 一遍一遍的去嘗試 嘗試失敗就回來換個方向嘗試 直到找出答案。
而遞迴中的回溯 更像一種要得到那種終止條件不得已的將問題規模縮小 當得到答案後 再一層一層擴大直到得出最終答案。
遞迴的兩種結題技巧:
1. 回溯到底得到臨界條件 利用臨界條件遞推到 規模為n的為題。 例如:
int find(int x) //查詢根結點
這是一段帶權並查集的路徑壓縮演算法。 在這段**中分為兩部分, find的函式中間截止 以上回溯,以下遞推 畫圖即可理解。
2. 在回溯的同時解決問題, 可能會不斷的進入臨界條件繼而返回,例如圖的遍歷, 但是圖的遍歷更像一種 一邊回溯一邊遞推一邊求解三者同時進行的思維模式。 這裡的遞推沒有具體值 是狀態量。 例子**後粘。
集合劃分問題
集合劃分問題 問題描述 n 個元素的集合可以劃分為若干個非空子集。例如,當n 4 時,集合可以劃分為15 不同的非空子集如下 其中,集合 由 1 個子集組成 集合 由2 子集組成 集合,由3子集組 成 集合,由4 子集組成。程式設計任務 給定正整數n 和m,計算出n元素的集合可以劃分為多少 不同的由...
集合劃分問題I
time limit 1000ms memory limit 32768k total submit 174accepted 64問題描述 n個元素的集合可以劃分為若干個非空子集。例如,當n 4 時,集合可以劃分為15 個不同的非空子集如下 演算法設計 給定正整數n,計算出n個元素的集合可以劃分為多...
集合劃分問題 演算法
問題描述 n個元素的集合可以劃分為若干個非空子集。例如,當n 4 時,集合可以劃分為15個不同的非空子集如下 其中,集合 由1個子集組成 集合,由2個子集組成 集合,由3 個子集組成 集合,由4個子集組成。程式設計任務 給定正整數n 和m,計算出n 個元素的集合可以劃分為多少個不同的由m 個 非空子...