• 递归


    递归是一种重要的数学思想,我们有时候会见到一个函数是用它本身定义的,这个时候
    我们就称它是递归的。现代的大多数语言都是支持递归的。递归有两个重要的问题需要
    确定。*首先*你必须要有某些基准情况,基准情况不需要递归就能解决;*其次*递归在
    回溯的时候一定能朝着基准方向前进。
        我们来举个例子说明一下递归:  这段代码是用来求阶乘的。当然这里只是举例子
    的时候对数值运算使用了递归,通常对于数值计算不要去使用递归。  
    
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    int fun(const int a);
    int main()
    {
        int n;
        cout << "请输入需要求的阶乘数:";
        cin >> n;
        cout << "结果是:" << fun(n) << endl;
        system("pause");
    }
        int temp;
    int fun(const int a)
    {
        if (0 == a)
        {
            return 1;//基准情形
        }
        else
        {
            temp = a * fun(a - 1);
            cout << "temp is " << temp << endl; //这行是为了打印递归回溯时的中间过程
            return temp;
        }
    }
    我们在来看另外一个很著名的问题,汉诺塔问题。这个问题我们也来使用递归求解。
    
    #include <iostream>
    using namespace std;
    void hanoi(int n, char a, char b, char c);
    int main()
    {
        int n;
        cin >> n;
        hanoi(n,'A','B','C');
        system("pause");
        return 0;
    }
    void hanoi(int n, char a, char b, char c)
    {
        if (1 == n)
        {
            cout << a << "->" << c << endl;
        }
        else
        {
            hanoi(n - 1, a, c, b);
            //hanoi(1, a, b, c);//为了减少调用函数的一点点开销,这里直接使用了输出。
            cout << a << "->" << c << endl;
            hanoi(n - 1, b, a, c);
            return;
        }
    }
    递归主要用于一下三种场合:
    1.使用递归代替多重循环,例如8皇后问题,本来需要使用8重循环来解决,现在使用循
    环解决,因为n是不确定的。所以我们来用递归写这个程序。代码如下:
    
    #include <iostream>
    using namespace std;
    void NQueen(int n);
    
    int n;
    int QueenPos[100];      //皇后的位置,皇后不能超过100
    int main()
    {
    
        cout << "请输入皇后个数:";
        cin >> n;
        NQueen(0);  //从第0行开始放皇后
        system("pause");
    }
    //这里使用递归来代替多重循环,N皇后的个数是不确定的,所以必须使用递归来代替多重循环
    void NQueen(int k)
    {
        int i;
        if (n == k)     //如果k等于n,那么说明n个皇后已经放好了,只需要输出就行了。
        {
            for (i = 0; i < n; i++)
            {
                cout << QueenPos[i] + 1 << " ";
            }
            cout << endl;
            return;
        }
        for (i = 0; i < n; i++)
        {
            int j;
            for (j = 0; j < k; j++)
            {
                //不能和前k个已经放好的皇后冲突
                if (QueenPos[j] == i || abs(QueenPos[j] - i) == abs(k-j))
                {
                    break;//位置冲突,不能放在这儿
                }
            }
            if (j == k) //没有执行break;所以不冲突,放置皇后
            {
                QueenPos[k] = i;
                NQueen(k + 1);//接着去放置下一个皇后
            }
        }
    }
    2.使用递归求解本身就是递归的一些事物。例如斐波那契数列从第2项起,有f(n) = f(n - 1)+f(n - 2);
    ```
    int temp;
    int Show(const int n)
    {   
        if (1 == n || 2 == n)
        {
            return 1;
        }
        temp = Show(n - 2) + Show(n - 1);//这里其实是重复计算了很多次,很不好,这就是前面所说的使用递归来进行数值计算的坏处。
        //好处就是看起来清晰明了,很简单。
        return temp;
    }
    ```
    3.使用递归将问题分解为规模更小的子问题来解决。
    爬楼梯,每次可以跨一级台阶,也可以跨两级台阶。求N阶的台阶共有几种走法。
    相信大家对于这个问题应该不陌生,这个问题常见于高中数学的排列组合当中。
    首先分阶问题,题目要求是N阶台阶的走法,我们来看第一步怎么走,
    当N>=2时,第一步有两种走法,走一级或者是走两级。
    所以我们分解为了N级走法 = 第一步走一级后,然后走剩下的N-1级 + 第一步走两级
    后,然后走剩下的 N - 2阶。到此,我们有了递推公式F(N)= F(N-1) + F(N -2);
    (和斐波那契数列一样的公式,但是它们的首项不一样)。我们还缺少基准条件。从分析
    中可以看到,我们可以使用 n == 2时,返回2,n == 1时返回1作为基准条件。那么
    代码如下:
    
    #include <iostream>
    
    int step(int n);
    int main()
    {
        int n;
        std::cin >> n;
        std::cout << step(n) << std::endl;
        system("pause");
    }
    int step(int n)
    {
        if (1 == n)
        {
            return 1;
        }
        if (2 == n)
        {
            return 2;
        }
        return step(n - 1) + step(n - 2);
    }
    
  • 相关阅读:
    Codeforces 777B Game of Credit Cards
    Codeforces 777A Shell Game
    零基础学贪心算法
    1283 最小周长
    容斥原理
    Humble Numbers(丑数) 超详解!
    1284 2 3 5 7的倍数
    1305 Pairwise Sum and Divide
    1347 旋转字符串
    HDU 2549 壮志难酬
  • 原文地址:https://www.cnblogs.com/zy666/p/10504304.html
Copyright © 2020-2023  润新知