1. 程式人生 > >從自然數1,2,...,n中任取r個數的所有組合

從自然數1,2,...,n中任取r個數的所有組合

【問題】利用遞迴方法找出從自然數1,2,…,n中任取r個數的所有組合
【例如】n=5,r=3,所有組合為:
在這裡插入圖片描述

方法一

【思路】

  1. 抽象問題:1,…,n中選r --> f(n,r)
  2. 從邊界n考慮,n要麼取,要麼不取 --> f(n,r) = f(n-1, r) + f(n-1, r-1)
  3. 退出條件:r==0時,就已經選完了
  4. 異常條件:n<r的時候
int a[50];

void f(int n,int r,int m) {
	int i;

	if (n<r) return ;

	if (r==0) {
		for (i=0; i<m; i++) printf("%d"
, a[i]); printf("\n"); } else { //選n a[m] = n; f(n-1, r-1, m+1); //不選n f(n-1, r, m); } }

方法二

【程式碼】

// 從1-n的數字中選r個數字
//	目前選的一個放入a[m]位置中
void C(int n, int r, int a[], int m) {
	int i;
	if (r==0) { //選完了
		//輸出
		for (i=0; i<m; i++) printf("%d", a[i]);
		printf("\n");
	} else {
		// 在[r,n]的範圍內選一個數字放入a[m]
for (i=n; i>=r; i--) { a[m] = i; C(i-1, r-1, a, m+1); } } }

【理解】用樹狀的形式輸出遞迴樹(先序)
樹狀的方式類似於這種https://blog.csdn.net/summer_dew/article/details/82937941
在這裡插入圖片描述

完整程式碼

方法一:

#include<stdio.h>

int a[50];

void f(int n,int r,int m) {
	int i;

	if (n<r) return ;

	if (r==0) {
		for (i=0; i<m; i++
) printf("%d", a[i]); printf("\n"); } else { //選n a[m] = n; f(n-1, r-1, m+1); //不選n f(n-1, r, m); } } int main() { int n,r; while (1) { printf("輸入n與r,空格分割\n>>> "); scanf("%d%d", &n, &r); f(n, r, 0); printf("\n"); } return 0; }

方法二:

#include<stdio.h>

// 從1-n的數字中選r個數字
//	目前選的一個放入a[m]位置中
void C(int n, int r, int a[], int m) {
	int i;

	// 以樹狀輸出遞迴樹
	/*
	for (i=0; i<m; i++) {
		printf("  ");
	}
	printf( "C(%d,%d, '" , n,r);
	for (i=0; i<m; i++) {
		printf("%d ", a[i]);
	}
	printf("', %d)",m );
	printf("\n");
	*/

	if (r==0) { // 選完了
		// 輸出
		for (i=0; i<m; i++) printf("%d", a[i]);
		printf("\n");
	} else {
		// 在[r,n]的範圍內選一個數字放入a[m]
		for (i=n; i>=r; i--) {
			a[m] = i;
			C(i-1, r-1, a, m+1);
		}
	}
}

int main() {
	int n,r;
	int a[50];
	while (1) {
		printf("輸入n與r,空格分割\n>>> ");
		scanf("%d%d", &n, &r);
		C(n, r, a, 0);
		printf("\n");
	}
	return 0;
}