由於我的記憶實在不好, 所以整理一下常用數學概念筆記方便日後參考. 這裡要說明的是 C(N,K) 問題.
C(N,K) - N 取 K 問題 :
考慮有問題如下 :
這邊的 C(N,K) 指的是從一個集合大小為 N 中取出 K 的 items 不考慮順序的可能組合. 考慮 N=3, K=2 的話可以如下圖理解 :
公式推導 :
由問題的提示我們可以知道 C(N,K) = C(N-1,K) + C(N-1,K-1). 但這個公式是怎麼來的呢? 從集合中的某個物件的角度來說, 你可以這麼看 :
那麼我們來看 (某個物件被選取的組合) 這個含意就是說 : 某一個物件被選取下, 剩下 K-1物件從 N-1物件中挑選的組合 -> C(N-1, K-1)
那麼 (某個物件沒被選取的組合) 也就是說 : 從 N-1 個物件 (去掉該被選取的物件), 取出 K 個物件 -> C(N-1, K)
所以最後我們得到 : C(N,K) = C(N-1,K) + C(N-1,K-1)
事實上這是一個很有名的定理 - 巴斯卡法則 :
在上面 "巴斯卡法則" 鏈結到 wiki 上面有對應的推導過程, 公式推導是死的. 重點要了解背後的物理意義. 我們知道公式如下 :
其中 n! 你可以理解在有 n 個物件的袋子依序取出 n 個物件的可能排列組合(考慮順序). 如 n=3 的話 :
(也就是說 n=3, n!=3*2*1)
那 m! 指的是我們取出來的 m 個物件中, 這 m 個物件的取出順序是不被考慮的; 而 (n-m)! 則是為了移除在 n! 中那些沒被選到的物件排列組合 :
範例代碼 :
下面使用代碼利用 Recursion 將公式 C(N,K) = C(N-1,K) + C(N-1,K-1) 實作出來, 可以發現函數 CSize() 得到的結果恰為上面公式 :
接著下面函數
C(int N, int K) 會幫我們從 Collection {1,2,...N} 取出 K 個 Items 中所有可能的 Combination (不考慮順序) :
接著我們可以如下執行上面兩個函數 :
並得到執行結果如下 :
下面使用代碼利用 Recursion 將公式 C(N,K) = C(N-1,K) + C(N-1,K-1) 實作出來, 可以發現函數 CSize() 得到的結果恰為上面公式 :
- /**
- * BD : C(N,K) = C(N-1,K) + C(N-1,K-1)
- * 1. You can treat C(N-1,K-1) -> Specific one is chosen from collection
. So K-1 left. from N-1 collection - * 2. You can treat C(N-1,K) -> The item 1 has specific one being chosen.
- * This item is the combination which not including that specific one.
- * @param col : The collection with size
. - * @param K : The number to pickup from collection
. - * @return The size of array of combination of pickup
items from collection size= C(N,K). - */
- public static int CSize(int N, int K)
- {
- if(N
return -1; // The collection size should not smaller than . - else if(N==K) return 1; // If the collection size
equals means only one possibility. - else if(K==0 || N==0) return 1; // If either collection size
=0 or K=0, return 1 as defined by question. - else // If the collection size
larger than , fit in the equation : C(N,K)=C(N-1,K) + C(N-1,K-1) - {
- return CSize(N-1,K)+CSize(N-1,K-1);
- }
- }
- /**
- * BD : Return all possible combination of C(N,K).
- * The collection is {1,2,...,N}.
- * @param N : The size of collection.
- * @param K : K items will be pickup.
- * @return The all possible combination of K items from collection.
- */
- public static Set
> C( int N, int K) - {
- Set
col = new HashSet (); - for(int i=1; i<=N; i++) col.add(i);
- return C(col, K);
- }
- public static Set
> C(Set int K){col, - Set
> comb = new HashSet >(); - // Remove duplicate items with different order. 321=123=231 etc.
- return _C(col, "", comb, K);
- }
- protected static Set
_genSet(Set int except)set, - {
- Set
newSet = new HashSet (); - for(Integer i:set) if(i!=except) newSet.add(i);
- return newSet;
- }
- public static Set
> _C(Set int K)curCol, String inSelect, Set > comb, - {
- if(curCol.size()>K)
- {
- for(Integer i:curCol)
- {
- if(inSelect==null) inSelect = "";
- Set
subSet = _genSet(curCol, i); - _C(subSet, inSelect, comb, K);
- _C(subSet, inSelect+i, comb, K-1);
- }
- return comb;
- }
- else if(curCol.size()==K)
- {
- for(int i:curCol) inSelect=inSelect+i;
- Set
charSet = new TreeSet (); - for(int i=0;i
- comb.add(charSet);
- return comb;
- }
- else
- {
- return comb;
- }
- }
- public static void main(String args[])
- {
- int N = 5, K=3;
- System.out.printf("\t[Info] N=%d; K=%d; C(N,K)=%d.\n", N, K, Combinatoric.CSize(N,K));
- Set
> colList = Combinatoric.C(N, K); - // Sorting the result
- Set
combInStr = new TreeSet (); - for(Set
chars:colList) { - StringBuilder sb = new StringBuilder("");
- for(Character c:chars) sb.append(c);
- combInStr.add(sb.toString());
- }
- // Printout the combinations
- for(String s:combInStr)
- {
- System.out.printf("\t%s\n", s);
- }
- }
沒有留言:
張貼留言