目录
92. 递归实现指数型枚举
从 1∼n1∼n 这 nn 个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 nn。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 11 个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤151≤n≤15
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
思路:
解题思路
我们可以从 1 ~ n 依次考虑每个数选还是不选,我们可以以一个树的形式来描述选还是不选的情况。对于每一种情况有三种状态可以选择:待考虑、选、不选。我们以 0 表示待考虑,1 表示选该位,2 表示不选。比如当 n = 3 的时候,我们画出的递归搜索树如下:
这其实就是一个 深度优先搜索 的过程,我们先考虑第一位,第一位有两种情况:左子树为不选第一位的情况,右子树为选第一位的情况;当不选第一位时又分成了两种情况,即在不选第一位的情况下第二位不选的情况(左子树)和第二位选的情况(右子树);然后又分成两种情况,选择第三位和不选择第三位。以上是整个左子树的分析情况,即刚开始第一位不选的情况。右子树第一位选择的情况下同理。
所以我们可以使用 dfs 来递归遍历所有的情况,首先递归遍历不选的情况,然后再递归遍历选择的情况。当每层递归到结束时依次遍历我们记录每个点的状态,如果是 1 我们就输出该数,否则就不输出该数。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 16;
int n;
int st[N];//状态:记录每个位置当前的状态:0表示还没考虑,1表示选它。2表示不选它
vector<vector<int>> ways;
void dfs(int u){
//判断边界
if(u>n){ //u>n表示已经到最后一位了
vector<int> way;
for(int i=1;i<=n;i++)
if(st[i]==1)
way.push_back(i);
ways.push_back(way);
return;
}
st[u]=2; //对于当前位置不选,置为 :2
dfs(u+1); //到下一个位置 第一个分支:不选
st[u]=0; //恢复现场
st[u]=1; //对于当前位置 选,置为 :1
dfs(u+1); //第二个分支:选
st[u]=0; //恢复现场
}
int main(){
cin>>n;
dfs(1);
for(int i=0;i<ways.size();i++)
{
for(int j=0;j<ways[i].size();j++) printf("%d ",ways[i][j]);
puts("");//输出回车
}
return 0;
}
这段代码是一个经典的递归实现,用于从 1 到 n 这 n 个整数中随机选取任意多个,然后输出所有可能的选择方案。
首先,在全局定义了一个常量 N 表示最大的整数个数,定义了一个数组 st 用来记录每个位置当前的状态:0 表示还没考虑,1 表示选它,2 表示不选它。同时定义了一个二维向量 ways 用来存储所有可能的选择方案。
接着有一个 dfs 函数,参数 u 表示当前处理的位置。在 dfs 函数中,首先判断是否已经到了最后一位,如果是,则将当前选取的数字存入 way 中,并将 way 存入 ways 中,表示找到了一种选择方案。然后进行递归调用,分别处理不选当前位置和选当前位置两种情况。
在主函数 main 中,首先读入整数 n,然后调用 dfs(1) 开始递归搜索所有可能的选择方案。最后遍历 ways 向量,输出每一种选择方案。
整体思路是通过递归的方式生成所有可能的选择方案,利用 st 数组来记录每个位置的选择状态,通过不断更新状态进行递归搜索。最终输出所有可能的选择方案。
运行结果: