AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

递归问题集锦(更新中)

作者: 作者的头像   无味 ,  2020-08-17 11:29:29 ,  所有人可见 ,  阅读 854


2


5

算法描述:

递归问题都可以先画出一个递归搜索树,然后再转换成代码!



例题:

1.Acwing 819. 递归求阶乘

#include<iostream>
using namespace std;
int fact(int n)
{
    if(n==1) return 1;
    return n*fact(n-1);
}
int main()
{
    int n;
    cin>>n;
    cout<<fact(n);
    return 0;
}

2.AcWing 820. 递归求斐波那契数列

#include<iostream>
using namespace std;

int fib(int n)
{
    if(n==1||n==2) return 1;
    else return fib(n-1)+fib(n-2);
}

int main()
{
    int n;
    cin>>n;
    cout<<fib(n);
    return 0;
}

其实用递归的效率是很低的,因为它同一个数值要算好多遍,所以用递归时也要考虑范围,这个题最大是30,还可以,当是42时,就超时了。


3.AcWing 821. 跳台阶

#include<iostream>
using namespace std;
int n,cnt=0;
void f(int k)
{

    if(k==n) cnt++;
    else if(k<n){
    f(k+1);
    f(k+2);
    }
}
int main()
{
    cin>>n;
    f(0);
    cout<<cnt;
}

4.AcWing 822. 走方格

刚开始的思路:

#include<iostream>
using namespace std;
int n,m,sum;
void f(int x,int y)
{
    if(x==n&&y==m) sum++;
    else if(x<n&&y<m){
        f(x,y+1);//右移;
        f(x+1,y);//下移;
    }
}
int main()
{
    cin>>n>>m;
    f(0,0);
    cout<<sum;
    return 0;
}

这样不管输入任何值,都是输出0;但又觉着思路没什么问题。所以就看了y总的讲解。

#include<iostream>
using namespace std;
int n,m,sum;
int dx[]={0,1},dy[]={1,0};//右移或者左移
void f(int x,int y)
{
    if(x==n&&y==m) sum++;
    else{
        if(y<m) f(x+dx[0],y+dy[0]);//右移;
        if(x<n) f(x+dx[1],y+dy[1]);//下移;
    }
}
int main()
{
    cin>>n>>m;
    f(0,0);
    cout<<sum;
    return 0;
}

看完后发现这两个else if一样啊,越想越一样。于是去求助别人,找到了问题所在。假设当n=2,m=3时,当执行到n=2,m=2时,在我想来,接下来会y+1,但其实不是,因为不满足x<n&&y<m,这样就会返回,所以当执行到最后(2,3)的前一步时都会返回,不会再继续往下执行了,sum不会++,所以就是0了。问题是自己推了好几遍,都默认能执行到2,3.可能陷入了思维定势了叭,让别人一看就看出来了。那么第一个思路要怎么改呢!

#include<iostream>
using namespace std;
int n,m,sum;
void f(int x,int y)
{
    if(x==n&&y==m) sum++;
    else if((x<=n&&y<m)||(x<n&&y<=m)){
        f(x,y+1);//右移;
        f(x+1,y);//下移;
    }
}
int main()
{
    cin>>n>>m;
    f(0,0);
    cout<<sum;
    return 0;
}

这样就ok了.


5.AcWing 823. 排列

刚开始思路:

#include<iostream>
using namespace std;

int n;
bool b[10]={0};

void f(int cnt){
    if(cnt==n) cout<<endl;
    else if(cnt<n){
        for(int i=1;i<=n;++i){
            if(!b[i])
                cout<<i<<" ";
                b[i]=true;
                //cnt++;
                f(cnt+1);
                b[i]=false;
        }
    }

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

但就是运行不出来,调试了一会也出不来,于是看了y总的代码:

#include<iostream>
using namespace std;

const int N=10;
int n;
void dfs(int u,int nums[],bool st[])
{
    if(u>n){
        for(int i=1;i<=n;++i)
            cout<<nums[i]<<" ";
    cout<<endl;
    }
    else
    {
        for(int i=1;i<=n;++i)
            if(!st[i]){
                nums[u]=i;
                st[i]=true;
                dfs(u+1,nums,st);
                st[i]=false;
            }
    }
}
int main()
{
    cin>>n;
    int nums[N];
    bool st[n]={0};

    dfs(1,nums,st);
    return 0;
}

QQ截图20200907075657.jpg
y总是先把每个数存到nums数组中,然后等存满了就输出,我是想着用i来输出,但没找到错在哪,于是照着y总的改了改,但还是不行,后边再回来看吧

#include<iostream>
using namespace std;
const int N=10;
int n;
void dfs(int u,bool st[])
{
    if(u>n)
        cout<<endl;
    else
    {
        for(int i=1;i<=n;++i)
            if(!st[i])
            {
                st[i]=true;
                cout<<i<<" ";
                dfs(u+1,st);
                st[i]=false;
            }
    }
}
int main()
{
    cin>>n;

    int nums[N];
    bool st[n]={0};

    dfs(1,st);
    return 0;
}

上面y总的nums[]和st[]是局部变量,下面是全局变量:

#include<iostream>
using namespace std;

const int N=10;
int n;
int nums[N];
bool st[N]={0};
void dfs(int u)
{
    if(u>n){
        for(int i=1;i<=n;++i)
            cout<<nums[i]<<" ";
    cout<<endl;
    }
    else
    {
        for(int i=1;i<=n;++i)
            if(!st[i]){
                nums[u]=i;
                st[i]=true;
                dfs(u+1,nums,st);
                st[i]=false;
            }
    }
}
int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

所以在dfs,bfs中数组定义还是全局变量的好,这样函数的参数就能少一点.


6.AcWing 92. 递归实现指数型枚举

这个题思路很多,一个是可以把每个1~n每个数都列出来,然后考虑每个数要不要选
qq_pic_merged_1599571142157.jpg

#include<iostream>
using namespace std;
int n;
const int N = 16;
int st[N];
void dfs(int u)
{
    if(u>n){
        for(int i=1;i<=n;++i)
            if(st[i]==1)
            cout<<i<<" ";

        cout<<endl;
        return;
    }
    else
    {
        st[u]=1;//第一个分支,选
        dfs[u+1];
        st[u]=0;//恢复现场

        st[u]=2;//第二个分支,不选
        dfs[u+1];
        st[u]=0;
    }
}
int main()
{
    cin>>n;
    dfs(1);
}

下面再说一下这个题的其他思路:

#include<iostream>
using namespace std;
int n;
void dfs(int u,int state)
{
    if(u==n)
    {
        for(int i=0;i<n;++i)
            if(state >> i & 1)
                cout << i+1<<' ';
        cout<<endl;
        return;
    }
    dfs(u+1,state);
    dfs(u+1,state|1<<u);
}
int main()
{
    cin>>n;
    dfs(0,0);//位运算,用二进制数表示一个集合,1的话表示存在,0的话表示不存在
    return 0;
}

#include<iostream>
#include<vector>
using namespace std;

int n;
vector<int> path;

void dfs(int u,int state)
{
    if(u==n)
    {
        for(auto x : path) cout<<x<<" ";
        cout<<endl;
        return;
    }
    for(int i=0;i<n;++i)
        if(!(state>>i&1))
        {
            path.push_back(i+1);
            dfs(u+1,state | (1<<i));
            path.pop_back();
        }
}
int main()
{
    cin>>n;
    dfs(0,0);
    return 0;
}

过了一段时间又做这个题:

#include<iostream>
using namespace std;
const int N = 15;
int st[N];
int nums[N];//用不到
int n;
void dfs(int m)
{
    if(m>n){
        for(int i=1;i<=n;++i)
            if(!st[i])
                cout<<i<<" ";
        cout<<endl;
    }
    st[m]=false;
    dfs(m+1);

    st[m]=true;
    dfs(m+1);

}
int main()
{
    cin>>n;

    dfs(1);
    return 0;
}

运行显示”Segmentation Fault”,什么也不输出

#include<iostream>
using namespace std;
const int N = 15;
int st[N];
int nums[N];//用不到
int n;
void dfs(int m)
{
    if(m>n){
        for(int i=1;i<=n;++i)
            if(!st[i])
                cout<<i<<" ";
        cout<<endl;
    }
    else{
        st[m]=false;
        dfs(m+1);

        st[m]=true;
        dfs(m+1);
    }
}
int main()
{
    cin>>n;

    dfs(1);
    return 0;
}

但是添加上else后就ac了…


7.凑算式 蓝桥杯2016初赛

这个题可以用暴力枚举,但很大概率会超时,这题也可以用递归来做,用递归的话中心思想就是上边的全排列问题的代码

#include<iostream>
using namespace std;
const int N = 10;
int num[N];
bool st[N];
int cnt=0;
void dfs(int step)
{
    if(step>=N){
        if(num[1]+1.0*num[2]/num[3]+(1.0*num[4]*100+num[5]*10+1.0*num[6])/(num[7]*100+num[8]*10+num[9])==10.0)
        {
//          for(int i=1;i<N;++i)
//              cout<<num[i]<<" ";
//          cout<<endl;

            cnt++;
        }   
    }
    else
    {
        for(int i=1;i<N;++i)
            if(!st[i]){
                st[i]=true;
                num[step]=i;
                dfs(step+1);
                st[i]=false;
            } 
    }
}
int main()
{
    dfs(1);
    cout<<cnt;
    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息