zoukankan      html  css  js  c++  java
  • 递归的思考

    本菜鸡终于开始学算法了,最近遇到递归的问题感觉难以理解,在这里写一些作题的错处与相关的总结



    **递归的总体思维:**
    1.找到停止递归的条件
    2.找到每一层递归之间的联系


    > 问题1**将多层循环简化**
    > 找出从自然数1 、 2、……、m中任取k 个数的所有组合。 例如m=5,k=3
    > 案例:输入5 3 的时候
    > 5 3
    5 4 3
    5 4 2
    5 4 1
    5 3 2
    5 3 1
    5 2 1
    4 3 2
    4 3 1
    4 2 1
    3 2 1


    分析:
    这个问题如果暴力枚举的话,是要用多重循环的,每一列对应一层循环,但是复杂度很大——————>简化:其实每一层的循环都是**相似处理方法**的循环,**每一层之间也有一定的联系**。
    在这个问题中:
    停止递归的条件是:当已经找到了k个数字的时候(这一步可以用计数器来进行记录)
    每一层之间的关系: 第一个数确定的时候,后面的数确定就转化为从k-1个数里找m-1个数的组合----------------->这是递归所体现出来的问题规模缩小

    每一层的输出:*当计数器计数到k的时候,终会输出,我们需要输出的数据:之前前面几层留存的数据,但是在递归过程中难以传递,——————》可以另外设置一个数组,做记忆的作用


    #include <iostream>
    typedef long long ll;
    using namespace std;
    int n,k,ans[100];//把第cur个数字储存起来
    void print()
    {
    
        for(int i=1;i<=k;i++)
            cout<<ans[i]<<' ';
            cout<<endl;
    
    }
    void dfs(int x,int cur)/*ra表示范围是1->x,cur表示他是第几个数*/
    {
        int i;
        if(cur==k+1)   //在cur更新到k的时候循环相应次数并且输出
                print(); 
        for(i=x;i>=1;i--)  /*每次进入循环总是递归到最小的一位开始输出*/
        {
            ans[cur]=i;
            dfs(i-1,cur+1);  //每次进入一个不是末位的数字都要进行一轮循环
        }
    
    }

     此处我自己对这个地方的递归算法一开始想不通的

    1.为什么递归函数入口放在for循环里面----

          在思路里提到过,其实这是一个多重循环,当需要进入递归入口,也就意味着还没到最里层的循环(最里层的函数循环结束之后,就会处处相应的结果啦!!),所以在for里面放递归函数,意味着         每进入一个新的递归函数,就进入了一层新的循环(这也是为什么结束条件是循环到第k数的时候)

    2.当一次递归走到结束之后,发生什么?

      由于递归函数是在for循环里面的,进入递归函数意味着在这一层函数的这一个i,这一次执行的过程中发生递归,(如果条件允许他可能这一层的每个i都会进入递归)

       当一层递归走到结束的时候,会返回到上一层循环,并且继续循环


    2.整数分解

    输出一个正整数n的所有整数和形式。如n=4 

    3
    3=3
    3=2+1
    3=1+2
    3=1+1+1


    分析:这道题是上一道题的一个升级,各层之间的关系与其递归的思想体现在:确定第一个数i之后,剩下的问题就是把n-i分解(问题规模缩小)

              此处要停止递归的条件:没东西可以分了,rest==0;


    #include <iostream>
    typedef long long ll;
    using namespace std;
    int n,rest,bit,store[100];
    
    void print()
    {
        int i=0;
        cout<<n<<'=';
        while(store[i]!=0)
            {
                cout<<store[i];
            if(store[i+1]!=0)
                cout<<'+';
                i++;
            }
        cout<<endl;
    }
    //每一位就是一个拆分的循环
    void dfs(int rest,int bit)   //由于是整数拆分,每次进入递归循环应该都是用rest
    {
        int i;
        for(i=rest;i>=1;i--)
        {
            store[bit]=i;    //储存该位
            if(rest-i==0)    //先写结束条件,单层循环里面(for)rest的值不会更新,所以一点过 
            {store[i+1]=0;     //设置输出断点
    print(); else dfs(rest-i,bit+1);//更新rest和bit的值,不要写成bit++的形式,只是传入值的副本变了 } // return 0; } int main() { ios::sync_with_stdio(0),cin.tie(0); cin>>n; rest=n; dfs(n,0); return 0; }

    出现的问题:

    这个代码写了超级久(T_T)

    问题1:使用了if(rest==0)为结束条件,错误想法:没东西可分,也就是rest==0,我的输出函数使用的是while循环,即使此处不结束,在调用dfs之后rest为0也会结束

    纠正:注意for循环的进入条件:注意递归函数进入条件和输出条件都在for循环里,rest==0,根本无法进入for循环,且多进一层递归函数会导致空间的浪费,记录一位就要检验一次rest还能不能分解

    问题2:在递归函数调用的时候采用了bit++这样的形式传递数据,在一次最内层函数结束之后,跳转到倒数第二层的数组储存位置会出问题,本来应该从0开始,但递归被调了多少次,就离谱多少步

    纠正:函数传递的是数据的副本,使用bit++或者++bit都会使得bit的值产生实际的变化

    问题3:一开始没有设置断点,有些数字储存比较远但并没有被覆盖,在输出的时候会产生错

      解决:1.增加断点

                2.输出的时候获得应输出的长度(bit)用for循环控制输出


    问题升级!!:不能输出重复的,比如4=3+1之后不可以输出4=1+3


    问题分析:在进入新一轮的循环中,我们要比上一轮确定的数字相等或者小


    代码改写:

    void dfs(int pre,int rest,int bit)   //由于是整数拆分,每次进入递归循环应该都是用rest
    {
        int i;
        for(i=pre;i>=1;i--)   //向下传递一个目前函数状态的参数 
        {
            if(rest-i<0)   continue;     //要保证rest-i不小于0,只有i很大的时候才会<0,所以coutine可以使得i不断减小,直到合适的值
            store[bit]=i;
            //if(bit>0&&store[bit]>store[bit-1]) continue;
            if(rest-i==0)    //先写结束条件,单层循环里面(for)rest的值不会更新,所以一点过 
            store[bit+1]=0,
    print(); else dfs(i,rest-i,bit+1);//更新rest和bit的值,不要写成bit++的形式,只是传入值的副本变了 }
  • 相关阅读:
    为图片指定区域添加链接
    数值取值范围问题
    【leetcode】柱状图中最大的矩形(第二遍)
    【leetcode 33】搜索旋转排序数组(第二遍)
    【Educational Codeforces Round 81 (Rated for Div. 2) C】Obtain The String
    【Educational Codeforces Round 81 (Rated for Div. 2) B】Infinite Prefixes
    【Educational Codeforces Round 81 (Rated for Div. 2) A】Display The Number
    【Codeforces 716B】Complete the Word
    一个简陋的留言板
    HTML,CSS,JavaScript,AJAX,JSP,Servlet,JDBC,Structs,Spring,Hibernate,Xml等概念
  • 原文地址:https://www.cnblogs.com/wengst/p/12580920.html
Copyright © 2011-2022 走看看