问题描述
问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
也就是要遵守两点要求:1、每次只能移动1个盘 。2、大盘不能放在小盘下面。
分析问题
假设盘子数为n。X、Y、Z是代表三根柱子。
Ⅰ、n=1时:1、X --> Z (移动1次)
Ⅱ、n=2时: 1、X --> Y
2、X --> Z
3、Y --> Z (移动1+1+1=3次)
Ⅲ、n=3时: 1、 X --> Z
2、X --> Y
3、Z --> Y
4、X --> Z
5、Y --> X
6、 Y --> Z
7、X --> Z (移动3+1+3=7次)
Ⅳ、n=4时: 1、X --> Y
2、X --> Z
3、Y --> Z
4、X --> Y
5、Z --> X
6、Z --> Y
7、X --> Y
8、X --> Z
9、Y --> Z
10、Y --> X
11、Z --> X
12、Y --> Z
13、X --> Y
14、X --> Z
15、Y --> Z (移动7+1+7=15次)
N:n=n时:(n-1)个盘子的移动次数 + 1 + (n-1)个盘子的移动次数 。
我们也可发现汉诺塔的规律:1个圆盘的次数21-1、 2个圆盘的次数22-1、 3个圆盘的次数23-1、 n个圆盘的次数2n-1。
而且可以发现的是移动中有一半的步骤是将盘子从 X 柱移往 Y 柱,也就是随着盘子的增加,所需的步数是指数上升的。
最后在人工移动时我们可以得出一个套路:先将 X 柱上的除最后一块盘子借助 Z 先移动到 Y 上,再将最后一块移到 Z 上,之后将 Y 柱视为 X ,重复上述,即可机械的完成移动。
以上总结为:
▼ 第一步:先把 X 上的前(n-1)个盘子放到 Y 上(占步数的一半)
▼ 第二步:再把 X 上最下面的盘子放在 Z 上
▼ 第三步:最后把 Y 上的(n-1)个盘子放在 Z 上
算法实现
int i=1;
void h(int n,char x,char y,char z){
if(n==1)
printf("%d、%c --> %c\n",i++,x,z);
else{
h(n-1,x,z,y);
printf("%d、%c --> %c\n",i++,x,z);
h(n-1,y,x,z);
}
}