acwing-蓝桥杯C++ AB组辅导课Day1-递归

感谢梦翔老哥的蓝桥杯C++ AB组辅导课~

省一刷200题        国赛拿成绩300题

比赛考察的是各种模型的熟练度,可以从dfs的角度比较各个模型与当前问题的匹配程度。

常见时间复杂度,根据时间复杂度可以判别是否可以选用这个解题思路

 写递归的时候,可以考虑将递归写成递归搜索树的形式,比较便于理解:

常见的数字:

递归实现指数型枚举:

递归的思路就是找到一个顺序不重不漏的遍历所有情况。本题的思路就是遍历每个位置,考虑每个位置选或不选的情况。

ac代码:

从第0个位置开始枚举,到第n-1的位置。先写边界,边界写完可以考虑上面图中的某个节点(红圈),设置某个位置的数字后递归回溯要还原现场。

递归是怎么实现回溯的呢?看下列代码,dfs(u+1)的位置,执行到此处代码会进入到新的函数当中,当dfs(u+1)执行结束的时候,会跳转到目前执行的下一行,为了不影响“选”的决策,需要把位置设置为原来的0。建议与上面的红圈图搭配着看比较清晰。

其实本题可以不用恢复现场,并且state[u] = 0 会被state[u] = 1 和下次dfs中的status[u]=2覆盖掉,因为最后输出只在递归树的末端,此时所有的位置都是1或者2,没有0。

递归实现排列型枚举:

做递归题建议先把递归搜索树写出来,明确思路。会简单很多。

思路1:枚举每个数字放到哪个位置 ×        由于题目要求输出字典序较小的数字,模拟了一下发现不能满足题目要求。

思路2:枚举每个位置放哪个数字 √

递归搜索树

AC代码:

时间复杂度分析:

根据递归搜索树分析,第一层O(n),第二层nxn,第三层nx(n-1)xn...        视频后面还有个证明,大概是使用了放缩,将红框的内容全部加起来,提出来个n,剩余的部分可以放缩成小于等于3倍的n!。所以最终的时间复杂度为nxn!。

习题1:

递归实现组合型枚举

思路:

一开始看到这个题,感觉跟例题里的枚举每个位置放哪个数基本一致,以为稍微改一下数组大小就行。但题意要求输出升序序列。所以在这基础上需要进行剪枝,123是可以的,132就是不行的。所以在填写位置的时候,将目前已经填写的数字(3)与即将要填入的数字(2)进行比较,如果已经填写的数字大于即将填入的数字,那就不能填,再往后看看有没有合适的数。

AC代码:

#include<bits/stdc++.h>

using namespace std;

vector<int> ans;
bool state[26];

int m,n;    //m表示位置个数,n表示数字个数

void dfs(int u){//枚举位置
    
    if(u == m){
        for(int i=0;i<m;i++){
            cout<<ans[i]<<" ";
        }
        cout<<endl;
        return;
    }
    int num = -1;
    for(int i=1;i<=n;i++){
        if(ans.size()!=0){
            num = ans[ans.size()-1];
        }
        if(!state[i]&&(i>num)){
            ans.push_back(i);
            state[i] = true;
            dfs(u+1);
            ans.pop_back();
            state[i] = false;
            
        }
    }
    
    
}

int main(){
    cin>>n>>m;
    
    dfs(0);
    
    return 0;
}

习题2:带分数

自己没想出来,引用一下人家的题解(没想到竟然如此暴力):

代码如下(代码自己想着敲得):

#include<bits/stdc++.h>

using namespace std;
vector<int> ans;
bool status[10];
int cnt = 0;
int calc(int i,int j){
    int num = ans[i];
    while(i<j){
        i++;
        num = num*10 + ans[i];
    }
    return num;
}

void dfs(int u,int target){
    if(u == 9){
        //对ans进行处理,走到这里正好凑够9位
        for(int i=0;i<7;i++){    //这里注意循环到7
            for(int j = i+1;j<8;j++){    //这里注意循环到8 不然没有c这个数了
                int a = calc(0,i);
                // printf("%d",a);  wc加了个printf就超时了
                int b = calc(i+1,j);
                int c = calc(j+1,8);
                if((a*c+b) == (target * c)) cnt++;
            }
        }
        return;
    }
    for(int i=1;i<=9;i++){
        if(!status[i]){
            ans.push_back(i);
            status[i] = true;
            dfs(u+1,target);
            status[i] = false;
            ans.pop_back();
        }
    }
}


int main(){
    int n;
    scanf("%d",&n);
    dfs(0,n);
    printf("%d",cnt);
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值