递归实现指数型枚举
题目链接:从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=15;
int st[N];
int n;
void dfs(int num){
if(num==n){
for(int i=0;i<n;++i) if(st[i]) printf("%d ",i+1);
puts("");
return;
}
dfs(num+1);//第1个分支:不选
st[num]=1;
dfs(num+1);//第2个分支:选
st[num]=0;//恢复现场
}
int main(){
scanf("%d",&n);
dfs(0);
return 0;
}
//只用到了bool vis[];num:判断(选或不选)到第几个位置了
其他写法:
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
scanf("%d",&n);
n=pow(2,n);
int cnt=1,num=1;
for(int i=0;i<n;++i){
int x=i;
cnt=1;
while(x){
if(x&1) printf("%d ",cnt);
x>>=1;
++cnt;
}
puts("");
}
}
//1~n 每个数选或不选,用0表示不选,1表示选,000...000~111...111 有2^n种方案。
递归实现排列型枚举
题目链接:把 1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=10;
int a[N];
bool st[N];
void dfs(int num){
if(num==n){
for(int i=0;i<n;++i) printf("%d ",a[i]);
puts("");
}
//依次枚举每个分支,即当前位置可以填哪些数
for(int i=0;i<n;++i){
if(!st[i]){
st[i]=1;
a[num]=i+1;
dfs(num+1);
st[i]=0;//恢复现场
}
}
}
int main(){
scanf("%d",&n);
dfs(0);
}
//用到了bool vis[] 和 int a[]
递归实现组合型枚举
题目链接:从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
输入样例:
5 3
输出样例:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=30;
int a[N];
void dfs(int x,int u){
if(u+n-x<m) return; //剪枝:能填的数小于空位数
if(u==m) {
for(int i=0;i<m;++i) printf("%d ",a[i]);
puts("");
return;
}
for(int i=x;i<n;++i){
a[u]=i+1;
dfs(i+1,u+1);
}
}
int main(){
scanf("%d%d",&n,&m);
dfs(0,0);
}
//用到了 start 和 int a[]
其他写法:转化成 从“指数型枚举”中挑出长度符合的答案
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=30;
bool vis[N];
void dfs(int x,int u){
if(u==m){
for(int i=0;i<n;++i) if(vis[i]) printf("%d ",i+1);
puts("");
return;
}
if(x==n) return;
vis[x]=1;
dfs(x+1,u+1);
vis[x]=0;
dfs(x+1,u);
}
int main(){
scanf("%d%d",&n,&m);
dfs(0,0);
}
//x:已经选了几个数, u:判断(选或不选)到第几个位置了