1. 程式人生 > 實用技巧 >【遞迴】P1157組合的輸出

【遞迴】P1157組合的輸出

題目相關

題目描述

排列與組合是常用的數學方法,其中組合就是從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≤rn)。

輸出格式

所有的組合,每一個組合佔一行且其中的元素按由小到大的順序排列,每個元素佔三個字元的位置,所有的組合也按字典順序。

**注意哦!輸出時,每個數字需要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

題目連結

P1157 組合的輸出 - 洛谷

分析

閱讀完題目,發現本題就是讓我們從 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;
}