• 汉诺塔问题:递归


    经典汉诺塔问题

    汉诺塔问题是经典的可以用递归解决的问题。

    汉诺塔(Hanoi)游戏规则如下:在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。计算需要移动的次数。

    我们先来对汉诺塔的步数进行一下递推。

    对于 n n n个盘子,我们可以把它分成 n − 1 n-1 n1个盘子和最后一个大盘子。设 F ( n ) F(n) F(n)为移动所需步数,那么对于 n n n个盘子来说所做的事情就是

    1. n − 1 n-1 n1个盘子从A柱借助C柱移动到B柱,这一过程移动的步数为 F ( n − 1 ) F(n-1) F(n1)
    2. 将大盘子从A柱直接移动到C柱,此时需要1步。
    3. n − 1 n-1 n1个盘子从B柱借助A柱移动到C柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n1)

    综合以上分析, F ( n ) = 2 F ( n − 1 ) + 1 F(n)=2F(n-1)+1 F(n)=2F(n1)+1。对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式。

    完整C++代码:

    #include 
    #include 
    using namespace std;
    
    void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
    {
      if (n == 0)
        return;
      Hanoi(a, c, b, n - 1);
      cout << a << " -> " << c << endl;
      Hanoi(b, a, c, n - 1);
    }
    int main()
    {
      int n;
      cin >> n;
      Hanoi('a', 'b', 'c', n);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如果要计算移动的次数可以定义一个全局变量ans来保存:

    #include 
    #include 
    using namespace std;
    int ans = 0;
    void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
    {
      if (n == 0)
        return;
      Hanoi(a, c, b, n - 1);
      ans++;
      cout << a << " -> " << c << endl;
      Hanoi(b, a, c, n - 1);
    }
    int main()
    {
      int n;
      cin >> n;
      Hanoi('a', 'b', 'c', n);
      cout << ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    输入:3
    输出:
    在这里插入图片描述

    改后的汉诺塔问题

    改后的汉诺塔问题如下:

    汉诺塔(Hanoi)游戏规则如下:在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,且限定圆盘只能够移动到相邻的柱子,即A柱子上的圆盘只能够移动到B,B柱子上的圆盘只能够移动到A或者C,C同理。并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。计算需要移动的次数。

    我们先来对改后的汉诺塔的步数进行一下递推。

    对于 n n n个盘子,我们还是可以把它分成 n − 1 n-1 n1个盘子和最后一个大盘子。设 F ( n ) F(n) F(n)为移动所需步数,那么对于 n n n个盘子来说所做的事情就是

    1. n − 1 n-1 n1个盘子从A柱借助B柱移动到C柱,这一过程移动的步数为 F ( n − 1 ) F(n-1) F(n1)
    2. 将大盘子从A柱直接移动到B柱,此时需要1步。
    3. n − 1 n-1 n1个盘子从C柱借助B柱移动到A柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n1)
    4. 将大盘子从B柱直接移动到C柱,此时需要1步。
    5. n − 1 n-1 n1个盘子从A柱借助B柱移动到C柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n1)

    综合以上分析, F ( n ) = 3 F ( n − 1 ) + 2 F(n)=3F(n-1)+2 F(n)=3F(n1)+2。对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式。

    完整C++代码:

    #include 
    #include 
    using namespace std;
    
    void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
    {
      if (n == 0)
        return;
      Hanoi(a, b, c, n - 1);
      cout << a << " -> " << b << endl;
      Hanoi(c, b, a, n - 1);
      cout << b << " -> " << c << endl;
      Hanoi(a, b, c, n - 1);
    }
    int main()
    {
      int n;
      cin >> n;
      Hanoi('a', 'b', 'c', n);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如果要计算移动的次数可以定义一个全局变量ans来保存:

    #include 
    #include 
    using namespace std;
    int ans = 0;
    void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
    {
      if (n == 0)
        return;
    
      Hanoi(a, b, c, n - 1);
      ans++;
      cout << a << " -> " << b << endl;
      Hanoi(c, b, a, n - 1);
      ans++;
      cout << b << " -> " << c << endl;
      Hanoi(a, b, c, n - 1);
    }
    int main()
    {
      int n;
      cin >> n;
      Hanoi('a', 'b', 'c', n);
      cout << ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输入:3
    输出:
    在这里插入图片描述

  • 相关阅读:
    持续集成与持续交付
    Android逆向题解 攻防世界难度4- Android2.0
    牛客网刷题笔记231112 最小k位数+二叉树层序遍历+SQL异常邮件概率
    第十三届蓝桥杯Java、C++、Python组国赛真题——最大公约数(三语言AC)
    SpringBoot项目打包部署
    206. 反转链表
    即时分账系统对B2B电商业务的重要性?
    剖析浏览器渲染与服务器渲染及其根本区别
    蓝桥杯单片机第九届省赛题详细讲解(彩灯控制器)
    [附源码]java毕业设计网上点餐系统
  • 原文地址:https://blog.csdn.net/subtitle_/article/details/133781032