题目:
从 1∼𝑛 中选出 𝑚 个数,要求同样的数字不能重复选择,按照字典序正序输出所有方案。
例如:从 1 到 4 中选出 2 个数,共有 6 种方法,按照字典序输出,依次为:
1 2 1 3 1 4 2 3 2 4 3 4
输入数据
输入共 2 个数 𝑛,𝑚 ,中间用空格分隔。( 1≤𝑚≤𝑛≤20 )
输出数据
按照字典序正序输出所有方案。
数据范围
12%2≤𝑛≤51≤𝑚≤556%2≤𝑛≤152≤𝑚≤5100%2≤𝑛≤202≤𝑚≤17
样例:
输入:
4 2
输出:
1 2
1 3
1 4
2 3
2 4
3 4
数据范围
从 1 到 4 中选出 2 个数,共有 6 种方法,按照字典序输出,依次为:
1 2
1 3
1 4
2 3
2 4
3 4
解法:
第一步:思考如何进行问题转化
初始问题为:在 1−𝑛 中选择 𝑚 个数。
如果第一个数选择了 1,则问题转为在 2−>𝑛 中选择 𝑚−1 个数。
如果第一个数选择了 3,则问题转为在 4−>𝑛 中选择 𝑚−1 个数。
如果第一个数选择了 𝑖,则问题转为在 (𝑖+1)−>𝑛 中选择 𝑚−1 个数。
选择区间中的 𝑛 是不变的,最小值是变化的,选了多少个数也是变化的,因此考虑将选择区间的最小值以及还要选多少个数作为递归的参数。
其余部分保存在全集变量中。用 𝐹(𝑚𝑖𝑛,𝑠𝑒𝑙) 处理选择区间最小值为 𝑚𝑖𝑛 ,还要选择 𝑠𝑒𝑙 个数的情况。
并利用循环 𝑖=(𝑚𝑖𝑛−>𝑛) ,递归到 𝐹(𝑖,𝑠𝑒𝑙−1) ,处理后面的选择。
第二步:思考如何设定递归的终止条件(基本情况)
以本题为例,当选择了 𝑚 个数时,即不再进行递归,即还剩 0 个数需要选择,此时输出之前所选中的数字。
所以递归到第 𝑚 层,就要终止递归,同时输出之前所选择的数字。
代码:
#include<bits/stdc++.h>
using namespace std;
int nums[21],n,m;
void F(int min,int sel){
if(sel==0){
for(int i=0;i<m;i++)
cout<<nums[i]<<" ";
cout<<endl;
return ;
}
for(int i=min;i<=n;i++){
nums[m-sel]=i;
F(i+1,sel-1);
}
}
int main(){
cin>>n>>m;
F(1,m);
return 0;
}
本文来源于51NOD,为@小罐头甜编辑