开卷门
题目:
从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
用模拟过程来解释递归过程:
假设一开始的三个位置 _ _ _
开始递归(假设我们先考虑 选 这个数这一种状态)
选择第一个数1:1_ _
选择第二个数2:12 _
选择第三个数3:123
第一次完成,输出:123
开始回溯:(建议根据代码进行理解,也就是那些数可以不选
回溯到第三次选择时不选择3: 12_
查看还有什么数可以选:不选
那么就是第三次不选——直接输出12
我们接着往回 溯
回溯到第二次选择时不选择2: 1_ _
查看还有什么数可以选:3, 不选
- 选择3:输出:13
(同理) - 不选:输出:1
解释为啥选过三之后不接着往下选了:(因为我们不选择2了1和3都被选择过了,所以下一个位置没有数可以选)
我们接着往回 溯
回溯到第一次选择时不选择1:
查看还有什么数可以选:2,3,不选
- 选择2: 那么此时为2_ _ ,因为我们还有其他数可以选,所以还得接着选
到达下一个位置,此时还有两种状态可选——3,或者不选- 选择3:输出23_
- 不选:输出2
- 选择3:那么此时为3 _ _ (因为我们没有其他数可以选了)
输出:3 - 不选:输出 :换行
解法一:递归实现
每次将不确定的整数的数量减少1,从而达到一个规模更小的子问题
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#define ll long long
#define PII pair<int, int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define IOS std::ios::sync_with_stdio(false);
using namespace std;
const int N = 101;
int n, m;
vector<int> num;
void dfs(int x)
{
if(x == n + 1) // 到达最后一个数
{
for(int i = 0; i < num.size(); i ++) // 输出此次结果
cout << num[i] << " ";
cout << endl;
return; // 回到上个位置
}
// 选择当前这个数
num.push_back(x); // 放入容器
dfs(x + 1); // 接着下一个数
num.pop_back(); // 回溯
// 不选当前这个数
dfs(x + 1); // 接着下一个数
}
int main()
{
IOS; // 加快程序输出效率
cin >> n >> m;
dfs(1); // 从第一个数开始
return 0;
}
解法二:位运算
因为n个数,每个数都有选和不选两种状态,所以n个数共有
2
n
2^n
2n种状态
通过所以每个数的如果选那么当前状态就是1,否则为0
每个状态都会由n位01串表示,1说明选择了这个数,0代表没有
那么我们只需要列举这
2
n
2^n
2n个01串,遍历找到为1的位置
int main()
{
cin >> n;
for(int state = 0; state < 1 << n; state ++)
{
for(int j = 0; j < n; j ++)
{
// 查看state的第j位是否为1
if(state >> j & 1) cout << j + 1 << " ";
}
cout << endl;
}
return 0;
}