描述
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
格式
输入格式
一行两个自然数n、r(1 < n < 16,1≤r≤n)。
输出格式
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
样例
输入样例
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
限制
时间限制: 1000 ms
内存限制: 65536 KB
#include <iostream>
#include <string.h>
using namespace std;
int a[16], b[16], j=0; //a[]用来记录元素是否找过,b[]用来找到的元素,j用来记数
//递归的三要素:递归出口、函数处理过程、递归参数
int back(int j, int n, int r) {
if (j == r) { //递归的出口,当找到一条符合条件的答案就输出
for (int k=0; k<j-1; k++) {
printf ("%d ", b[k]);//注意输出格式,值后面有两个空格,有些博文只有一个,具体怎样,其以你所在的oj平台为主
}
printf ("%d\n", b[j-1]);
return 0;
}
for (int i=1; i<=n; i++) { //递归函数的处理过程
if (!a[i] && b[j-1] <i ) { //没有找过,而且,上一次找的数要比i小,因为会出现排列的情况,这包含里2 1 3这种情况,不属于组合
b[j] = i; //赋值
a[i] = 1; //记录已找到一个元素
back(++j, n, r); //开始递归,查找下一个
a[i] = 0; //递归回来后,该位置要归0
j--; //而且j记数-1
}
}
}
int main()
{
int n, r;
scanf ("%d %d", &n, &r);
memset(a, 0, sizeof(a)); //初始化值为0
memset(b, 0, sizeof(b)); //初始化值为0
back(j, n, r); //其实n, r可以不做参数,设为全局变量即可
return 0;
}
对回溯有疑惑的,可以看看该博主的博文:LeetCode--回溯法心得