题目地址:
https://www.acwing.com/problem/content/95/
从 1 ∼ n 1∼n 1∼n这 n n n个整数中随机选出 m m m个,输出所有可能的选择方案。
输入格式:
两个整数
n
,
m
n,m
n,m,在同一行用空格隔开。
输出格式:
按照从小到大的顺序输出所有方案,每行
1
1
1个。首先,同一行内的数升序排列,相邻两个数用一个空格隔开。其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如1 3 5 7
排在1 3 6 8
前面)。
数据范围:
n
>
0
n>0
n>0
0
≤
m
≤
n
0≤m≤n
0≤m≤n
n
+
(
n
−
m
)
≤
25
n+(n−m)≤25
n+(n−m)≤25
思路是DFS。由于是组合枚举,所以顺序是不要紧的,所以在DFS的时候,要设定一个开始搜索的下标,搜出来的组合都是下标递增的,这样可以避免重复搜索。代码如下:
#include <iostream>
using namespace std;
int n, m;
int a[30];
// u是枚举起点,即本轮枚举是枚举u, u + 1, ... ,n这些数,cnt是已经枚举了多少个数
void dfs(int u, int cnt) {
// 如果已经枚举足够了,则得到了一个组合,输出之
if (cnt == m) {
for (int i = 0; i < m; i++) cout << a[i] << ' ';
cout << endl;
return;
}
// 否则开始从u进行枚举。这里有个优化是,还能供枚举的数一共有n - i + 1个,
// 还需要枚举m - cnt个数,所以有n - i + 1 >= m - cnt,可以定下i的上界
for (int i = u; i <= n + 1 + cnt - m; i++) {
a[cnt] = i;
dfs(i + 1, cnt + 1);
}
}
int main() {
cin >> n >> m;
dfs(1, 0);
return 0;
}
时间复杂度 O ( m ( n m ) ) O(m{n\choose m}) O(m(mn)),空间 O ( m ) O(m) O(m)。