0 题目来源

acwing

1 涉及到的知识点

递归、剪枝

2 题目描述

从1∼n这n个整数中随机选出m个,输出所有可能的选择方案。

3 输入输出

输入格式:
两个整数n,m,在同一行用空格隔开。
输出格式:
按照从小到大的顺序输出所有方案,每行1个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。
数据范围:
n>0,
0≤m≤n,
n+(n−m)≤25

4 样例

输入样例:
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

5 思路

本题主要思路为,依次为给定的m个位置挑选n个数。
递归搜索树为:m层,每层的每一分支有最多n个孩子
由于本题要求后面的数字要大于前面的数字,因此设置一个maxnum来记录当前的最大数字,并且在之后层中遍历[题解]递归实现组合型枚举 - 图1的数字

剪枝
为了加快递归速度,本题可以剪枝。
如果当前已经选择的数字个数加上还未选择的数字个数小于需要选择的数字个数,则说明此情况不满足题意,因此可以在递归开头直接返回。
其中,当前已经选择的数字个数为[题解]递归实现组合型枚举 - 图2(由于当前还未进行选择,因此减一),还未选择的数字个数为[题解]递归实现组合型枚举 - 图3(由于接下来要在for循环中遍历[题解]递归实现组合型枚举 - 图4的数字),需要选择的数字个数为[题解]递归实现组合型枚举 - 图5,因此剪枝的条件为[题解]递归实现组合型枚举 - 图6,即[题解]递归实现组合型枚举 - 图7

6 代码

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. int n,m;
  5. int maxnum;
  6. vector<int> vec;
  7. void dfs(int num)
  8. {
  9. if(n+num-maxnum<m)return;//剪枝
  10. if(num==m)//递归退出
  11. {
  12. for(int i=0;i<vec.size();i++)
  13. cout<<vec[i]<<' ';
  14. cout<<endl;
  15. return;
  16. }
  17. for(int i=maxnum+1;i<=n;i++)//子分支
  18. {
  19. maxnum=i;
  20. vec.push_back(i);
  21. dfs(num+1);
  22. vec.pop_back();
  23. maxnum=vec[vec.size()-1];
  24. }
  25. }
  26. int main()
  27. {
  28. cin>>n>>m;
  29. dfs(0);
  30. return 0;
  31. }