【遞迴】P1157組合的輸出
阿新 • • 發佈:2020-12-01
題目相關
題目描述
排列與組合是常用的數學方法,其中組合就是從n個元素中抽出r個元素(不分順序且 r ≤n),我們可以簡單地將n個元素理解為自然數1,2,…,n從中任取r個數。
現要求你輸出所有組合。
例如n=5,r=3所有組合為:
12 3 , 1 2 4 , 1 2 5 , 1 3 4 ,1 3 5 , 1 4 5 , 2 3 4 , 2 3 5 , 2 4 5 , 3 4 5
輸入格式
一行兩個自然數n,r(1<n<21,0≤r≤n)。
輸出格式
所有的組合,每一個組合佔一行且其中的元素按由小到大的順序排列,每個元素佔三個字元的位置,所有的組合也按字典順序。
**注意哦!輸出時,每個數字需要3個場寬,pascal可以這樣:
write(ans:3);
輸入輸出樣例
輸入
5 3
輸出
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
題目連結
分析
閱讀完題目,發現本題就是讓我們從 1 ~ n個數中選出r個數,輸出所有的組合,並且部分順序。且對輸出做出了一定的要求,元素要從小到大排列,且佔三個場寬。
佔三個場寬可以使用printf來實現,注意加上標頭檔案cstdio
printf("%3d",x);//輸出元素佔3個場寬
選擇的過程和 全排列問題有些類似。每次都是從一堆數字中選一個出來加入組合,等挑完r個元素後,就輸出。過程中要注意一點,他需要從小到大排列。那麼我們可以使得挑選的數字比前一個選的大,這樣就可以了。而不是說,選出所有的數字之後再去篩選,這樣反而麻煩很多。
for(int i=ranks[pre]+1;i<=n;i++){//遍歷比前一個元素大的數字
ranks[pre+1]=i;//存到組合序列中
...
}
程式碼實現
#include <iostream> #include <cstdio> using namespace std; int n,r; int ranks[25]={0};//存放選好的r個數字 void dfs(int sel){ //已選好sel個數字 if(sel==r){ for(int i=1;i<=r;i++){ printf("%3d",ranks[i]); } cout<<endl; }else{//還未挑選好 //挑選第sel+1個數字 //其中的元素按由小到大的順序排列 // 我的第sel+1個數字> 第sel個 ranks[sel] for(int i=ranks[sel]+1;i<=n;i++){//第sel+1 個數字可能的值 //挑選i 存放進ranks陣列中 //第sel+1 個 => ranks[sel] ranks[sel+1]=i; //已經選好了sel+1個數字 //遞迴呼叫 ,繼續尋找下一個 dfs(sel+1); } } } int main() { cin>>n>>r; dfs(0); return 0; }