遞迴列印組合

2021-07-29 19:51:04 字數 2000 閱讀 1202

列印組合問題:給出數n和k(1<=k<=n),求出c(n,m)的所有組合並列印.例如n=5,k=3,則所有的組合為:

5 4 3

5 4 2

5 4 1

5 3 2

5 3 1

5 2 1

4 3 2

4 3 1

4 2 1

3 2 1

如果只是求出組合數,那麼就是簡單的[單向遞迴]問題,因為存在遞推公式:c(n,k) = c(n-1,k-1) + c(n-1,k)且c(n,1)=n,c(n,0) = 0;

但是,[列印出所有組合]比求組合數難度稍大.

這裡我們按照逆序來列印,即按照數字遞減的順序列印.

我的思路是,第乙個元素可以為n,n-1,...,k這幾個元素,假若第乙個元素選的是x,則第2~k個元素可以在(x-1)到1中間選,直到選完倒數第二個元素(假設為y),最後乙個元素可以分別列舉出來,分別可以為y-1,...,1這幾個元素.列印的時候,只需要在分別列印第乙個元素~倒數第二個元素,再迴圈加上最後乙個元素的每一種可能.

按照以上思路,求5選3的所有組合的過程為,從5 4 3 2 1中選出3個元素的所有組合:

5 4 [3 2 1]————選出5 4之後,再分別加上 3 2 1就構成了3個組合方式

5 3 [2 1]   ————選出5 3之後,再分別加上2 1 就構成了2個組合方式

5 2 [1]      ————選出5 2之後,再分別加上1就構成了1個組合方式

4 3 [2 1] 

4 2 [1]

3 2 [1]

後面的3個同理.

**如下:

#includeusing namespace std;

int tot;

void f(int a,int n,int k,int cur)//cur為當前陣列所在位置

}int main()

輸入6和3的執行結果如下:

重要參考:

下面是我無可奈何的思路,雖然也可以得到正確結果,但是不如上述方法簡潔和"正確",簡而言之,就是:誤打誤撞,從n個元素選出了k個元素,由於遞迴不正確,所得到的的多個組合有的不符合要求,但是結果中包含所需的所有組合,所以可以按照某種方式選擇出所需要的組合.

選擇的**如下:

#include#includeusing namespace std;

int tot = 0;

int cmp(int a,int b)

void f(int a,int n,int k,int cur)

}int main()

輸入5和3的結果如下:

可以看到,有一些不符合要求的,例如5 3 3,還有,4 3 2 和 4 2 3應該認為是相同的組合,只需要輸出一次就行,所以我們通過兩個篩選,排除這兩種不符合要求的組合方式.

篩選1:組合中有重複元素的排除.

篩選2:組合中的元素必須按照逆序排序,否則排除.例如4 2 3會被排除,4 3 2會被保留.

加上篩選之後的**:

#include#includeusing namespace std;

int tot = 0;

int cmp(int a,int b) //從大到小排序

void f(int a,int n,int k,int cur)

}int main()

輸入5和3的結果為:

遞迴與組合

福利彩票和體育彩票近兩年比較火暴,相應在vb論壇上大家討論也較多。其實選擇彩票與集合選擇子集相同道理。下面給出一種vb的遞迴演算法 雖然明知存入陣列會加快運算速度,但最終也沒能滿意地實現,請大家多多指教。另外,效率確實不高 option explicit private sub command1 c...

JS列印組合功能

1.區域性列印 即想列印什麼地方就列印什麼地方 解決辦法 將不想列印的地方隱藏起來 在將不想列印的地方控制起來 不需要列印的地方 2.引用組建 webbrowser控制項 關於這個元件的用法,列舉如下 webbrowser.execwb 1,1 開啟 web.execwb 2,1 關閉現在所有的ie...

遞迴學習 組合 全組合排列

sample input 1 2 3 sample output include using namespace std const int len 10 int n int mat len int result len bool used len 初始值為false,表示都沒有使用過 void s...