3597: 【搜索】桐桐的组合
时间限制: 1 Sec 内存限制: 64 MB题目描述
排列与组合是常用的数学方法,桐桐刚刚学会了全排列,就想试试组合,组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
输入
两个整数n和r(1≤r≤n≤20)。
输出
输出所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
样例输入
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
分析
考察深度搜索,搜索+回溯。
参考代码
这个代码的b数组没有用,修改见下一个代码。
/** n=4,r=3 dfs(1) deep=1, i=1//前一个选定的数加1开始循环,前第一次选定的数是0 ans[1]=1, b[21]={0,1,0,0,0,……}, dfs(2) deep=2, i=2//前一个选定的数加1开始循环,前一个选定的数是1 ans[2]=2, b[21]={0,1,1,0,0,……}, dfs(3) deep=3 i=3, ans[3]=3, b[21]={0,1,1,1,0……}, deep=r=3 printf,1,2,3 b[21]={0,1,1,0,0,……},//回溯,因为1,2{3,4}循环完,后面还得循环1,3,{4} i=4//继续for循环 ans[3]=4 b[21]={0,1,1,0,1,……} deep=r=3 printf,1,2,4 b[21]={0,1,1,0,0,……}//回溯 i=5>n dfs(2)//第三个数循环完了,返回到第二个数 b[21]={0,1,0,0,0,……}//回溯 i=3, ans[2]=3, b[21]={0,1,0,1,0,……} dfs(3) …… …… */ #include <iostream> #include <stdio.h> #include <string.h> using namespace std; int n,r; int ans[21]; int b[21];//全局变量自动初始化为0 void dfs(int deep); int main() { scanf("%d%d",&n,&r); dfs(1); return 0; } void dfs(int deep){ int i; /** 从上一个选定数加1开始循环,比如, 1,2,3;1,2,4;1,2,5;是从2加1开始循环的 */ for(i=ans[deep-1]+1;i<=n;i++){ if(!b[i]){ ans[deep]=i; b[i]=1; if(deep==r){ for(int j=1;j<=r;j++){ printf("%3d",ans[j]); } printf(" "); } else{ dfs(deep+1); } b[i]=0; } } }
删掉b数组,09.14
/** 上面的代码只是标记b的元素然而并没有用到标记数组所以删了也能AC n=4,r=3 dfs(1) deep=1, i=1//前一个选定的数加1开始循环,前第一次选定的数是0 ans[1]=1, dfs(2) deep=2, i=2//前一个选定的数加1开始循环,前一个选定的数是1 ans[2]=2, dfs(3) deep=3 i=3, ans[3]=3, deep=r=3 printf,1,2,3 i=4//继续for循环 ans[3]=4 deep=r=3 printf,1,2,4 i=5>n dfs(2)//第三个数循环完了,返回到第二个数 i=3, ans[2]=3, dfs(3) …… …… */ #include <iostream> #include <stdio.h> #include <string.h> using namespace std; int n,r; int ans[21]; void dfs(int deep); int main() { scanf("%d%d",&n,&r); dfs(1); return 0; } void dfs(int deep){ int i; /** 从上一个选定数加1开始循环,比如, 1,2,3;1,2,4;1,2,5;是从2加1开始循环的 */ for(i=ans[deep-1]+1;i<=n;i++){ ans[deep]=i; if(deep==r){ for(int j=1;j<=r;j++){ printf("%3d",ans[j]); } printf(" "); } else{ dfs(deep+1); } } }