在大一时,就遇到此类问题,发现不会解决。现在还是不会,但是通过查阅相关资料,对于此类问题的解决已经有了头绪。
起源
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
抽象为数学问题
如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数
那么,我们来寻找下规律:
n=1:
A --> B (重点)
sum = 1
n=2:
A --> B
A --> C (重点)
B --> C
sum = 3
n=3:
A --> C
A --> B
C --> B
A --> C (重点)
B --> A
B --> C
A --> C
sum = 7
...
通过上述分析,可以发现:
1个圆盘,sum = 2^1-1
2个圆盘,sum = 2^2-1
3个圆盘,sum = 2^3-1
...
n个圆盘,sum = 2^n-1
故:sum = 2^n - 1
我们可以把解决步骤分为3个:
1)把 n-1 个盘子,由A移动到B盘
2)把第n个盘子,由A移动到C盘
3)把 n-1 个盘子,由B移动到C盘
解析:
(1)中间的一步是把最大的一个盘子由A移到C上去
(2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到 了B上
(3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上
主要需要注意上述的中间一步;且都要移动到目标塔(C塔)
#include<stdio.h>
#include<math.h>
static count = 0;
void move(int n, char sour, char des) {
count++;
printf("第%d次移动,把%d号圆盘从 %c --> %c\n",count, n, sour, des);
}
/*
n:圆盘数
a:源
b:过渡
c:目标
*/
void hanNuoTa(int n,char a,char b,char c) {
if (n == 1) {
move(1, a, c);
}
else {
hanNuoTa(n - 1, a, c, b);
move(n, a, c);
hanNuoTa(n - 1, b, a, c);
}
}
int main() {
int n;
char a, b, c;
/*
Visual Studio 2017 后强制要求使用 scanf_s (线性安全输入),
来避免内存访问越界的问题。
scanf_s 要求在录入字符串的时候都要指定缓冲区的大小。
*/
scanf_s("%d %c %c %c", &n, &a,4, &b,4, &c,4);
hanNuoTa(n,a,b,c);
return 0;
}
测试运行:
各位读者,一定要动手写代码!!!看10遍,不如写1遍!!!