汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?
要把64个圆盘从a柱子移动到c柱子上,第一步应该怎么做?虽然可以肯定,第一步唯一的选择是移动a最上面的那个圆盘,但是应该将其移到b还是c呢?很难确定。因为接下来的第二步、第三步……直到最后一步,看起来都是很难确定的。能立即确定的是最后一步:最后一步的盘子肯定也是a最上面那个圆盘,并且是由a或b移动到c——此前已经将63个圆盘移动到了c上。
一股脑地考虑每一步如何移动很困难,我们可以换个思路。先假设除最下面的盘子之外,我们已经成功地将上面的63个盘子移到了b柱,此时只要将最下面的盘子由a移动到c即可。
当最大的盘子由a移到c后,b上是余下的63个盘子,a为空。因此现在的目标就变成了将这63个盘子由b移到c。这个问题和原来的问题完全一样,只是由a柱换为了b柱,规模由64变为了63。因此可以采用相同的方法,先将上面的62个盘子由b移到a,再将最下面的盘子移到c……对照下面的过程,试着是否能找到规律:
- 将b柱子作为辅助,把a上的63个圆盘移动到b上
- 将a上最后一个圆盘移动到c
- 将a作为辅助,把b上的62个圆盘移动到a上
- 将b上的最后一个圆盘移动到c
- .....
也许你已经发现规律了,即每次都是先将其他圆盘移动到辅助柱子上,并将最底下的圆盘移到c柱子上,然后再把原先的柱子作为辅助柱子,并重复此过程。
下面代码实现
#include <stdio.h>
void hanoiMove(char start,char object) {//hanoiMove函数表示 将哪个柱子上的圆盘移到哪个柱子上
printf("%c -> %c\n", start, object);
}
void hanoi(int count,char start,char assist,char object) {//start表示起始柱,assist表示辅助柱,object表示目标柱
if (count == 1) {
printf("%c -> %c\n", start, object);
/*
* 当n == 1时只需要把起始柱上的圆盘直接放到目标柱就好
*/
}
else {
hanoi(count - 1, start, object, assist);
/*
* 设想一下 n != 1 要想完成任务必然有n-1个圆盘在辅助柱上,第n个在目标柱上,
* 当n != 1我们肯定要想办法把n-1个圆盘放到辅助柱上
* 我们可以通过以 <-目标柱 作为 辅助柱-> 来完成这个想法
*/
hanoiMove(start, object);
/*
* 在上一步我们已经完成了准备工作(已经把n-1个圆盘放到辅助柱上了)
* 这个时候我们只需要把第n个直接放到目标柱上
*/
hanoi(count - 1, assist, start, object);
/*
* 最后只需要将放在辅助柱上的n-1个圆盘放到目标柱上
* 结束
*/
}
}
int main() {
int count;
while (1) {
printf("请输入圆盘个数:");//输入提示
scanf("%d", &count);
if (count > 0) {
break;
}
else {
printf("输入错误请重新输入!\n");//输入错误提示
}
}
hanoi(count, 'a', 'b', 'c');
/*
* 传四个参数
* 第一个 count代表圆盘的个数
* 第二个 字符a代表起始柱的名称
* 第三个 字符b代表辅助柱的名称
* 第四个 字符c代表目标柱的名称
*/
return 0;
}