文章目录
一、递归实现指数型枚举
比如:输入n,输出幂集
输入3
输出:
空
1 2 3
1 2
1 3
1
2 3
2
3
输出的排列是2^3=8就是指数级别
那么怎么用递归实现呢?
搜索树
代码分析
递归每次传入的参数为访问到第几个数了,如:pownum(1)表示刚开始选择,pownum(2)表示选择到了第二个数
递归的出口应该就是当x>3,这个时候就打印输出
在每一次选择标记后,递归进入下一个选择,那么我们就需要还原现场,以保证回溯回来的时候发生错误。
代码实现如下
#include<iostream>
using namespace std;
#define MAX 100
int n;
int st[MAX];//这个用来存状态,最后选择状态就可以了
void pownum(int x){
if(x>n){
for(int i=1;i<=n;i++){
if(st[i]==1)cout<<i<<" ";
}
cout<<endl;
return;
}
st[x]=1;
pownum(x+1);
st[x]=0;
st[x]=2;
pownum(x+1);
st[x]=0;
}
int main(){
cin>>n;
cout<<"递归实现指数型枚举"<<endl;pownum(1);
return 0;
}
二、递归实现排列型枚举
如:输入n,输出全排列
比如:输入3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
题目分析
很明显,这也可以是一个选择问题,可以弄一个数组来存数字,然后递归判断选和不选
比如刚进入递归我们先选1,标记1已经选过了就是s[1]=true,继续选2,选3,最后打印1 2 3
由于选完 2之后就只剩下1个空位,只能选3,所以递归到1 2 3后,回到不选2,则选3,最后只能选2,最后打印1 3 2。
出口条件还是x>n,然后打印输出
每一次都要进行选择数字,选过的就不选了,所以进入循环后,如果循环到了这个数,没有被标记,就可以让它标记选择,然后让b[X]=i,就可以进入下一个递归
还是要记得恢复现场,防止回溯时出现问题
代码如下(示例):
#include<iostream>
using namespace std;
#define MAX 100
int n;
//实现排列型枚举,比如实现全排列
bool s[MAX];
int b[MAX];
void perm(int x){
if(x>n){
for(int i=1;i<=n;i++)cout<<b[i]<<" ";
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!s[i]){
s[i]=true;
b[x]=i;
perm(x+1);
s[i]=false;
}
}
}
int main(){
cin>>n;
cout<<"递归实现排列型枚举"<<endl;perm(1);
return 0;
}
3.递归实现组合型枚举
这个和前面两个枚举相似,就不多赘述
代码如下(示例):
#include<iostream>
using namespace std;
#define MAX 100
int n;
//实现组合型枚举,比如在五个数,选3个数,这里n==5,则默认是从1,2,3,4,5里面选数,其他情况只需要加个数组存数就可以了
int c[MAX];
int r;
void comb(int x,int start){
if(x>r){
for(int i=1;i<=r;i++)cout<<c[i]<<" ";
cout<<endl;
return ;
}
for(int i=start;i<=n;i++){
c[x]=i;
comb(x+1,i+1);
c[x]=0;
}
}
int main(){
cin>>n;
cin>>r;
cout<<"递归实现组合型枚举"<<endl;comb(1,1);
return 0;
}
总结
其实递归实现枚举,就两种情况
1.枚举每个数在哪个位置
比如:幂集问题,就是有3个位置,让数选择位置放进去
2.枚举每个位置放哪个数
比如:排列问题,就是确定了位置,把数放到对应的位置上