题目描述
从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数n。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好1个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤15
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
题目分析
本题的指数型枚举就是相当于枚举整个集合{1, 2, …, n}的所有子集
递归求指数型枚举就是回溯法的应用
区间[1, n]中的每个数都有两种选择:选择此数和不选择此数
所有递归过程为:
①选择此数,递归求解,恢复现场
②不选此数,递归求解,恢复现场
递归终点:1–n中所有数都枚举过即枚举数cur>n,直接终止
c++代码实现
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 20;
bool st[N];//表示数是否被选择过
void dfs(int cur, int n) {
if(cur > n) {
for(int i = 1; i < cur; ++i) {
if(st[i]) printf("%d ", i);
}
puts("");
return ;
}
//枚举第cur个数
st[cur] = true;//选择数cur
dfs(cur+1, n);
st[cur] = false;//不选数cur,并恢复现场
dfs(cur+1, n);
}
int main() {
int n;
scanf("%d", &n);
dfs(1, n);
return 0;
}
非递归算法
一个大小为集合的所有子集数为2n
对应了0—2n所有数的的二进制表示,每个数的二进制表示看成一个子集
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int n;
cin>>n;
for(int i = 1; i <= 1<<n; ++i) {
for(int j = 0; j < n; j ++) {
if(i>>j & 1){
printf("%d ", j+1);
}
}
puts("");
}
return 0;
}