题目信息
从 1−n 这 n 个整数中随机选取 m 个,每种方案里的数从小到大排列,按字典序输出所有可能的选择方案。
输入
输入两个整数 n,m。(1≤m≤n≤10)
输出
每行一组方案,每组方案中两个数之间用空格分隔。
注意每行最后一个数后没有空格。
样例输入
3 2
样例输出
1 2
1 3
2 3
样例输入2
5 3
样例输出2
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
数据规模与约定
时间限制:1 s
内存限制:256 M
100% 的数据保证 1≤m≤n≤10
分析解答
为完成本次枚举,我们不妨还是定义数组arr[10]
int arr[10];
然后我们不妨先定义一个输出函数print_it,用于输出枚举得到的结果。
每调用一次它,应当输出数组0~m-1的位置的值。
void print_it(int m) {
for (int i = 0; i <m; i++) {
if (i)cout << " ";
cout << arr[i];
}cout << endl;
}
下面我们设计递归函数f(i,j,n,m)。其含义可理解为:
从 1−n 这 n 个整数中随机选取 m 个,每种方案里的数从小到大排列,按字典序输出所有可能的选择方案的时候,数组下标为i处的值大于等于j时,i处~m-1处枚举的所有方案的集合。
当我们进行枚举时,显而易见的,仅枚举arr数组中0~m-1的位置,以确保每种方案中包含m个数。所以,枚举过程中当下标i==m时,我们应当停止,并输出当前方案。故添加:
void f(int i, int j, int n, int m) {
if (i == m) {
print_it(m);
return;
}
return;
}
然后我们进行枚举部分的代码书写,其原理与上一篇指数型枚举相似,在本帖不多赘述,将上一篇贴在这里,大家可以试着举一反三:
与指数型枚举略有不同的是,在进行组合型枚举的循环条件中,必须保证k~n之间的数的数量足够能填满数组i~m-1位置。于是将n-k>=m-1-i也设置为循环条件。(k为枚举过程中填入数组的单个数)
ok于是我们完善递归函数
void f(int i, int j, int n, int m) {
if (i == m) {
print_it(m);
return;
}
for (int k = j; k <= n && n - k >= m-1 - i; k++) {
arr[i] = k;
f(i + 1, k + 1, n, m);
}
return;
}
最后我们补上主函数,整理得到完整代码:
#include<iostream>
using namespace std;
int arr[10];
void print_it(int m) {
for (int i = 0; i <m; i++) {
if (i)cout << " ";
cout << arr[i];
}cout << endl;
}
void f(int i, int j, int n, int m) {
if (i == m) {
print_it(m);
return;
}
for (int k = j; k <= n && n - k >= m-1 - i; k++) {
arr[i] = k;
f(i + 1, k + 1, n, m);
}
return;
}
int main() {
int n,m;
cin >> n >> m;
f(0, 1, n,m);
return 0;
}