什么?汉诺塔问题原来这么简单!(图文并茂)计算机算完要207年!
什么?我的电脑计算汉诺塔要整整207年!汉诺塔是一个经典的数学益智游戏,起源于法国数学家卢卡斯提出的传说。游戏规则要求将叠放在A柱上的N个不同大小的圆盘全部移动到C柱,每次只能移动一个盘且大盘不能叠在小盘上。该问题可采用递归算法解决,时间复杂度为O(2^n),移动次数随盘数呈指数增长。传说中64个金盘需要5849亿年才能移动完毕,远超宇宙年龄。汉诺塔问题不仅展示了递归思维的魅力,也是编程学习中的重
一.什么是汉诺塔?
汉诺塔,也被称为河内塔(Tower of Hanoi),是一个根据传说形成的数学问题:
有三根杆子A、B、C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
①每次只能移动一个圆盘;
②大盘不能叠在小盘上面。
可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
问题为:应该以何种方式移动?最少要移动多少次?

二.趣味故事
最早发明这个问题的人是法国数学家爱德华·卢卡斯。根据他的描述,传说越南河内(地点众说纷纭,还有说法是在印度北部)某间寺院有三根银棒,上串 64 个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。
不过,一点也不用担心。因为如果传说属实,按照一秒可以移动一个盘子来计算,需要整整5849亿年才能完成。整个宇宙至今不过才137亿年,地球诞生至今也就不过46亿年!
三.算法求解
3.1 基本思想
汉诺塔问题的解法思想是递归。假设有 A、B、C 三个塔,A 塔有 N 块盘,目标是把这些盘全部移到 C 塔。那么先把 A 塔顶部的 N−1 块盘移动到 B 塔,再把 A 塔剩下的大盘移到 C,最后把 B 塔的 N−1 块盘移到 C。




①总是把N-1个盘子从A起始柱,借助B中转柱,移动到C目的柱。
②再把A起始柱最大的盘子移动到C目的柱。
③这时,B上面剩下的N-1个盘子,要移动到C柱上。那么B就变为了起始柱,A为中转柱,C为目的柱。
如此递归地使用下去, 就可以求解。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void move(char pos1, char pos2)
{
printf("%c->%c\t", pos1, pos2);
}
void Hanoi(int n, char pos1, char pos2, char pos3)
{
if (n == 1)
{
move(pos1, pos3);
}
else
{
Hanoi(n - 1, pos1, pos3, pos2);
move(pos1, pos3);
Hanoi(n - 1, pos2, pos1, pos3);
}
}
int main()
{
Hanoi(3, 'A', 'B', 'C');
return 0;
}
3.2运行结果

四.时间复杂度
递归的过程需要在每个阶段进行两次递归调用(分别处理 n-1 个盘子)。因此,总的移动次数为 2^n - 1。这个递归算法的时间复杂度是 O(2^n),随着盘子数量的增加,移动次数呈指数增长。
这里我只呈现了3个盘子的运行结果,如果是64个盘子,那么程序就会一直跑啊跑,我们来看看计算机移动完这64个盘子需要多久。

这里是笔者电脑上的处理器,主频2.70GHz。
可以看到该处理器需要运行207年才可以移动完这64个盘子,大家207年后见,届时评论区公布运行结果!
通过递归解决汉诺塔问题,不仅能帮助我们理解递归算法的基本思想,也能加深对递归函数调用栈的理解。这个问题在编程面试中经常出现,也是学习递归算法的经典范例。
希望你在阅读本文后能够理解递归的基本概念,动手实践实现其他递归问题。如果你有任何问题或者改进建议,欢迎在评论区留言,和大家一起讨论。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)