回溯算法
第一题:组合问题
链接:递归实现指数枚举
解题思路:
dfs:
保存状态可以选择数组或者选择二进制
#include<iostream>
using namespace std;
int n;
int a[16];
int b[16];
void dfs(int x,int y,int z)
{
//当a数组中的数满足每次I的个数,也是一种情况需要输出
if(x==z){
//循环输出A数组中保存的数
for(int i=0;i<x;i++)
cout<<a[i]<<" ";
cout<<endl;
return;
}
//由于是递增的数列,然后就需要从Y往n的方向移动取
for(int i=y;i<=n;i++){
//如果B[Y]里面的为0,表示这个数没有用过,1表示用过
if(b[i]==0){
//把次数保存
a[x]=i;
//记录I这个数已经用过
b[i]=1;
//继续保存第二个,数也是需要从下一个开始枚举
dfs(x+1,i+1,z);
//在回归的时候需要还原
b[i]=0;
}
}
}
int main(){
cout<<endl;
cin>>n;
//记录数组A中的个数,当i=1时数组A里面就只有1个数,当数组i=2时A数组中有两位数。。。
for(int i=1;i<=n;i++){
//0代表的是A数组的下标,1表示的是B数组的小标,B[y]也就是判断这个数是0就是还没用过,是1表示用过
dfs(0,1,i);
}
return 0;
}
通过二进制保存状态:状态压缩
#include<iostream>
using namespace std;
int n;
//x是枚举的数,Y的二进制的位数上1的位置数是记录着哪些数被选择
void fun(int x,int y){
//直到n个数全部枚举完
if(x==n){
//输出结果
for(int i=0;i<n;i++){
//查看状态上的二进制位数上哪些是1
if(y>>i & 1)
cout<<i+1<<" ";
}
cout<<endl;
return ;
}
//不选择当前的x数
fun(x+1,y);
//选择当前的x数,先把1向前移x位,在通过或与之前的结合
fun(x+1,y | 1<<x);
}
int main(){
cin>>n;
fun(0,0);
return 0;
}
第二题:排列问题
链接:递归实现排列枚举形
解题思路:
dfs:
没有递增条件,可以直接采用填空的方法
#include<iostream>
using namespace std;
int n;
int a[10];
int b[10];
void dfs(int x){
if(x==n){
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
return ;
}
for(int i=1;i<=n;i++){
if(b[i]==0)
{
a[x]=i;
b[i]=1;
dfs(x+1);
b[i]=0;
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
第二种状态压缩
#include<iostream>
using namespace std;
int n;
int a[10];
void dfs (int x,int y){
if(x==n){
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
for(int i=0;i<n;i++){
if((y >>i & 1) ==0){
a[x]=i+1;
dfs(x+1,y | 1 <<i);
}
}
}
int main(){
cin>>n;
dfs(0,0);
return 0;
}