汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
(此处图文介绍来自于百度百科)
先上实现代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable : 6031);//用于取消关于scanf的警告(编译器VS2022)
#include <stdio.h>
int hanoi(unsigned int x) {
if (x > 1) {
return 2 * hanoi(x - 1) + 1;
}
else if(1 == x) {//递归的最后一层,也就是1 == x
return 1;
}
else {//输入0层,代码要健壮
return 0;
}
}
int main() {
unsigned int floor = 0;
scanf("%u", &floor);//输入的层数
printf("移动次数:%u\n", hanoi(floor));
return 0;
}
(本人也是萌新,若有错误请指出,见谅!😋)
想必很多人主要是不理解这个公式是怎么来的
2 * hanoi(x - 1) + 1;
看完下面分析想必就应该能得出答案。
首先我们将三根柱子分别命名为A,B,C
A柱为刚开始盘子放的柱子
C柱为目标转移的柱子
B为过渡柱
汉诺塔这个游戏要求必须大盘在下,小盘在上。
单从流程上来说明这个游戏无非就是先把最大的盘子放到C柱
再把第二大的盘子放到C柱...直到把最小的盘子放到C柱上
而最大的盘子一定是在最底层的,转移到另一个柱子也是最底层
故我们可以想象一下,把最大的盘从A放到C上,无论有多少个盘子,一定是如图的
【 图中用数字表示盘子大小,最小盘代号1,最大盘代号n(也代表了一共有多少个盘子) 】
我们将前(n-1)层看作一个整体,可见想将第n层由A移至C,则一定要把前(n-1)移动到B
此处实际上最大的盘子是不是只需要移动1步?即由A到C。
当最大的盘子放到C柱后,然后就没这个最大的盘子什么事了
明白了这个,就可以继续思考,放到最大盘C柱之前是不是也动不了最大盘?
即除非出现这个情况外最大盘一直处于移动不了的状态
【当然这个是建立在步骤最简的基础上,如果有甚者把最大盘先移到B柱上步骤肯定会增多】
既然如此,我们想要转移最大盘由A至C,要先完成将前(n - 1)层由A转移至B
不论过程,当我们完成将前(n - 1)层由A转移至B,然后再将最大盘由A转移至C后
只需将前(n - 1)层由B转移至C
也就是说这个过程其实就分为了3步:
1>将(n - 1)层由A转移至B让出位置
2>将最大盘由A转移至C
3>将前(n - 1)层由B转移至C
我们设完成将前(n - 1)层由一个柱子移到另一个柱子的步骤有[n - 1]步
为什么这里说是“由一个柱子移到另一个柱子的步骤”,而不是指明由A至B或由B至C呢?
思考一下,实际上我们所谓的A,B,C真的很特殊,相互之间不同吗?
为使问题更清晰,我们先考虑这个问题,在明白了“最大盘不怎么动,其实只移动一步”后,我们不如假设它<不存在>
最大盘既然不能移动,自然不能影响前(n - 1)层的移动,我们就可以将其看作不存在
这样看想必会清晰很多
再看我们将前(n - 1)由A整体移动到B,再整体由B移动到C有区别吗?
显然是没有区别的
话归原题,我们可以得出结论完成n层盘子的汉诺塔游戏需要2 * [n - 1] + 1步
【
公式其中2是由A到B 和 由B到C 两个整体步骤
1是将最大盘由A移动到C这一步
】
明白了上述的,我们乘热打铁,完成将前(n - 1)层A到B(或B到C),和将前(n - 1)层由A移动到C有区别吗?显然也是没有的
即完成一个 n层盘子的汉诺塔游戏需要的步骤 其实就是 完成一个 (n - 1 )层盘子的汉诺塔游戏需要的步骤 * 2 + 1
同理完成一个 (n - 1 )层盘子的汉诺塔游戏需要的步骤 其实就是 完成一个 (n - 2 )层盘子的汉诺塔游戏需要的步骤 * 2 + 1
......
完成一个 2层盘子的汉诺塔游戏需要的步骤 其实就是 完成一个 1层盘子的汉诺塔游戏需要的步骤 * 2 + 1
由此想必大家就可以理解为什么可以用递归和公式2 * hanoi(x - 1) + 1是怎么来的了
而完成一个1层盘子的汉诺塔游戏需要的步骤只需要1步,这也就是为什么return 1;
以两层的汉诺塔游戏举例
绝不是我想偷懒(手动滑稽),是因为这个可以以小见大,很能体现完成一个n层盘子的汉诺塔游戏需要的三步法
只要将第一层看作前(n -1)层,将第二层看作最大盘
完成这个游戏核心思想就是
1>将(n - 1)层由A转移至B让出位置
2>将最大盘由A转移至C
3>将前(n - 1)层由B转移至C
附有3层的手绘图,应该可以帮助大家理解“各个柱子其实是没什么区别的”,不嫌我字丑的可以看看🙈🙈🙈