跳至主要內容

汉诺塔

李超2024年11月15日大约 3 分钟教学文档递归分治法

汉诺塔问题解答

题目描述

汉诺塔是一个古老的数学问题:有三根杆子 A,B,C。A杆上有 N个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C杆:

  • 每次只能移动一个圆盘
  • 大盘不能叠在小盘上面

提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。

解题思路

  1. 递归基础情况:当只有一个圆盘(n==1)时,直接将其从源塔座x移动到目标塔座z,并增加步骤计数器sum。如果此时sum等于用户指定的目标步骤数m,则输出该步骤的信息。

  2. 递归步骤

    • 首先,将上面的n-1个圆盘视为一个整体,通过目标塔座z的辅助,将它们从源塔座x移动到辅助塔座y。
    • 然后,将剩下的最大圆盘(第n个)从源塔座x移动到目标塔座z,并增加步骤计数器sum。如果此时sum等于m,则输出该步骤的信息。
    • 最后,将之前移动到辅助塔座y的n-1个圆盘整体,通过源塔座x的辅助,移动到目标塔座z。
  3. 全局变量:使用全局变量sum来跟踪已经执行的步骤数,以及全局变量m来存储用户希望查看的步骤数。

  4. 输出:在递归结束后,输出完成汉诺塔所需的总步骤数sum。

具体代码实现

#include <iostream>
using namespace std;

// 全局变量
int sum = 0, m;

// 递归函数
void hanoi(char x, char y, char z, int n) {
  if (n == 1) { // 递归基础情况
    sum++; // 增加步骤数
    if (sum == m) { // 如果当前步骤是用户指定的步骤
      cout << "#" << n << ": " << x << "->" << z << endl; // 输出步骤信息
    }
  } else { // 递归步骤
    hanoi(x, z, y, n - 1); // 将n-1个圆盘从x移动到y,z作为辅助
    sum++; // 增加步骤数
    if (sum == m) { // 如果当前步骤是用户指定的步骤
      cout << "#" << n << ": " << x << "->" << z << endl; // 输出步骤信息(注意:这里输出的是最大圆盘的移动)
    }
    hanoi(y, x, z, n - 1); // 将n-1个圆盘从y移动到z,x作为辅助
  }
}

int main() {
  int n; // 圆盘数量
  cin >> n >> m; // 输入圆盘数量和用户希望查看的步骤数
  hanoi('A', 'B', 'C', n); // 执行汉诺塔操作
  cout << sum << endl; // 输出完成汉诺塔所需的总步骤数
  return 0;
}

注意

  • 本代码中的 #include <bits/stdc++.h> 被替换为标准的 #include <iostream>,因为前者不是标准C++库,且在部分编译环境中可能不被支持。
  • 确保输入了合理的 nm 值,其中 n 表示圆盘数量,m 表示用户希望查看的特定步骤编号(如果不需要查看特定步骤,可忽略此参数或设置为一个大于总步骤数的值)。
上次编辑于: 2025/1/13 09:18:24
贡献者: molittle,zilizhou