问题 G: 【例5.2】组合的输出
时间限制: 1 Sec 内存限制: 128 MB提交: 51 解决: 33
[提交][状态][讨论版][命题人:quanxing]
题目描述
排列与组合是常用的数学方法,其中组合就是从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)。
输出
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
样例输入
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
解题思路:递归搜索。开一个数组vis用来标记每个数是否已经使用,为了保持从小到大输出,每次递归后for循环从上一次保存的数+1开始搜索。
#include <bits/stdc++.h> using namespace std; int n,r,a[25]; bool vis[25];//来记录各个数字是否被访问 void dfs (int dep)//dep代表搜索的深度,即当前数组a添加了多少个数 { for (int i=a[dep-1]+1;i<=n;++i)//从上一个添加的数+1开始搜索数字 { if (!vis[i])//如果这个数字没被访问过 { a[dep]=i;//将这个数字添加到a里面去 if (dep==r)//如果添加的数字达到r个,把他们输出 { for (int j=1;j<=r;++j) printf("%3d",a[j]); printf(" "); } else dfs(dep+1);//如果达不到r个继续添加 vis[i]=0;//回溯,清空当前状态,把vis[i]设为没有访问过。 } } } int main() { while (~scanf("%d%d",&n,&r)) { memset(a,0,sizeof a); memset(vis,false,sizeof vis); dfs(1);//从第一个数开始搜索 } return 0; }