Code up【遞歸入門】組合的輸出

題目描述

排列與組合是常用的數學方法,其中組合就是從n個元素中抽出r個元素(不分順序且r < = n),我們可以簡單地將n個元素理解爲自然數1,2,…,n,從中任取r個數。 
現要求你不用遞歸的方法輸出所有組合。 
例如n = 5 ,r = 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 

輸入

一行兩個自然數n、r ( 1 < n < 21,1 < = r < = n )。

輸出

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

參考鏈接:

https://blog.csdn.net/qq_20679687/article/details/89411791

分析:題目要求使用非遞歸的方法輸入;

注意到,組合的輸出,是當前未被輸出的最小的序列,然後從最後面一位開始自增到n。然後再找到此時未被輸出的最小序列,重複操作。

具體分析可以看代碼。

void print(int a[],int r)
{
	for(int i=1;i<=r;i++)
		cout<<a[i]<<" ";
	cout<<endl;
}
bool handle(int a[],int r,int n)
{
	if(a[r]<n)
		a[r]++;    //從最後一個自增到n
	else{    //如果最後一位不能增加,找此時最小序列
		int i=1;
		while(a[r-i]==n-i&&r-i>0)    //找到改變的位置
			i++;
		if(r-i==0)	return false;	   //如果找不到說明已經沒有序列
		a[r-i]++;
		while(i){        //處理一下找到位置後面的數字
			a[r-i+1]=a[r-i]+1; 
			i-- ;
		}
	}
	return true; 
}
 
int main(){
	int n,r;
	cin>>n>>r;
	int a[100];
	for(int i=1;i<=r;i++)
		a[i]=i;    //先給一個最小的序列
	print(a,r);
	while(handle(a,r,n))    //處理
		print(a,r);

	return 0;

} 

個人覺得關鍵代碼

        int i=1;
        while(a[r-i]==n-i&&r-i>0)    //找到改變的位置
            i++;

這裏這樣理解,因爲序列是按小到大,那麼 r-i 意味着從最大位開始遞減 ,n-i是該位可以接受的最大的數字。

那麼如果相等,該位就不能變換,只能在往下找。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章