#include<iostream>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=16;
int n;
int st[N];//记录当前的状态,0表示还没选他,1表示选他,2表示不选他
void dfs(int u)
{
if(u>n)
//表示到最后一位了,到边界,不能递归了,要return
{
//从前往后依次枚举一下每个位置
for(int i=0;i<=n;i++)
if(st[i]==1) //如果为1,就表示选了他
printf("%d",i); //就把它输出
//输完这个方案后要输入一个回车
printf("\n");
//return之前需要把这个方案输出,这个方案就是从前往后遍历一下每一位,看一下这一位有没有选
return;
}
//如果我不选他的话,表示我选的是2,就递归下一个位置
st[u]=2; //这三排表示第一个分支不选
dfs(u+1);
st[u]=0; //回复现场
//但是如果在a位置,他有两种选择,选还是不选,如果不选的话,当前位置就不得标注,就需要回到a的位置将它设置为0,因此就需要用到回溯置0操作
st[u]=1; //这三排表示第二个分支选它
dfs(u+1);
st[u]=0;
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
递归算法二
//1.依次枚举每个数放到哪个位置
//2.依次枚举每个位置放到哪个数
//联想到递归搜索树
//注意:如果题目提到了让我们输出字典序最小的方案的话,那我们就只需要从小到大遍历每一个数,就一定是字典序最小的
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=10;
int n;
//注意:如果变量定义成下面这种全局变量的话,初始值为0和false
int st[N]; //st为0表示还未放数,1-n表示放了哪个数
bool used[N]; //true表示用过,false表示还没用过
void dfs(int u)
{
if(u>n)
{
for(int i=1;i<=n;i++)printf("%d",st[i]);//打印方案
puts("");
return;
}
//接下俩就是枚举一下每个分支及当前位置上可以填哪些数,从小到大来枚举
//首先要找出所有没有用过的数
for(int i;i<=n;i++)
if(!used[i]) //如果当前位置是没有用过的,那就说明当前位置可以填这个数,可以成为一个分支,如果当前这个位置成为这个数的话,我们需要去更新一下状态
{
st[u]=i; //u这个位置填的这个数
used[i]=true; //表示这个位置已经被用过了
dfs(u+1);
//下面的操作是恢复现场工作
st[u]=0;
used[i]=false;
}
}
int main(){
scanf("%d",&n);
dfs(1);
return 0;
}
递归算法三:组合数递归
算法描述:输入,n和m,n表示总数,m表示n中截取的个数
比如n=5,m=3
输出位数为3的所有排列数,比如123,124,125这种,按照字典序从小到大进行排列的所有结果
//递归算法三
//递归组合数
//排列是考虑顺序的,但是组合是不考虑顺序的,从一段数据中选出几个来进行组合,然后这几个数优惠则合成什么数,比如5个里面选3个,就会产生的结果有,123,132,124之类的所有是三个数的排列数,这里选出来的三个数不固定,只知道选了三个
//这时候算法的思想是比如选出3个数,比如第一第二个数字固定,然后将第三个位置自由变换,比如前面12固定,然后第三个数字开始枚举可以选3,可以选4,可以选5进行填充到第三个位置,然后其他其他位置也是一样的
//组合数递归的思想:每次新加的数大于前面一个数
//这种递归组合数一般可以组合成一棵树的结构,也就是顶端是组合的树干,然后组合数的每个位置,依次向下进行枚举,只有当后一个枚举数b大于前一个枚举数a的时候,才把后一个位置的b位置进行枚举插入
/*组合型枚举的步骤:
1.首先确定组合的位置,也就是定义个数组来存一下这几个位置
2.定义个东西表示当前枚举到哪个位置
3.判断当前最小可以到哪个数枚举,越界边界问题
*/
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=30;
int n,m;
int way[N]; //用way来表示方案
void dfs(int u,int start) //第一个数表示当前枚举到了哪一个位置,第二个数start的话表示从哪个数开始枚举
{
if(u==m+1) //这时表示已经选了m个数了,此时就把方案输出
{
for(int i=1;i<=m;i++)printf("%d",way[i]);
puts(""); //表示输出一个回车
return; //这就是边界
}
//如果还没有选m个数的话,就要从开始进行枚举,也就是从start开始枚举
for(int i=start;i<=n;i++)
{
//每次这个数放到way中去
way[u]=i; //当前存入的数是i
dfs(u+1,i+1); //因此就要从下一层i+1开始枚举
//最后恢复一下现场,保证每个点往下走的时候都是公平的,从当前位置往下走的时候,当前位置要保证是空的,所以在做完当前位置的操作后,要恢复为空
way[u]=0;
}
}
int main(){
scanf("%d%d",&n,&m); //读入n,m
dfs(1,1); //dfs传3个参数,3个位置,词句从第一个位置的第一个数开始枚举
return 0;
}