acwing蓝桥杯课——递归算法

#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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值