汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
汉诺塔问题计算量相当庞大,我们可以大致评估一下:如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。n=64时,假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:18446744073709551615秒
这表明移完这些金片需要5845.54亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。
【思路】
假设有 A, B, C 三根柱子,盘子原先在 A 柱子上,要将盘子全部移动到 C 柱子上,B 柱子是辅助作用,我们取 n = 1, n = 2, n = 3,进行简单分析推到:
当 n = 1时,直接将 A 上盘子移动到 C 柱子上,只需要1步;
当 n = 2时,将 A 最上的一个移动到 B 柱子上,再将 A 下面的盘子移动到 C 柱子上,最后将 B 柱子上的盘子移动到 C 上,共需要3步;
当 n = 3时,详细说明 n = 3的情况:
A)将A上的n-1(等于2,令其为n`)个圆盘移到B(借助于C),步骤如下:
(1)将A上的n`-1(等于1)个圆盘移到C上。 (2)将A上的一个圆盘移到B。 (3)将C上的n`-1(等于1)个圆盘移到B。
B)将A上的一个圆盘移到C。
C) 将B上的n-1(等于2,令其为n`)个圆盘移到C(借助A),步骤如下:
(1)将B上的n`-1(等于1)个圆盘移到A。 (2)将B上的一个盘子移到C。 (3)将A上的n`-1(等于1)个圆盘移到C。到此,完成了三个圆盘的移动过程。
从上面分析可以看出,当n大于等于2时,移动的过程可分解为三个步骤:第一步把A上的n-1个圆盘移到B上;第二步把A上的一个圆盘移到C上;第三步把B上的n-1个圆 盘移到C上;其中第一步和第三步是类同的。当n=3时,第一步和第三步又分解为类同的三步,即把n`-1个圆盘从一个针移到另一个针上,这里的n`=n-1。由于初始条件 n = 1,n = 2时均成立,故对于任意 n 递推形式也成立。
下面是Java代码实现:
汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
汉诺塔问题计算量相当庞大,我们可以大致评估一下:如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。n=64时,假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:18446744073709551615秒
这表明移完这些金片需要5845.54亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。
【思路】
假设有 A, B, C 三根柱子,盘子原先在 A 柱子上,要将盘子全部移动到 C 柱子上,B 柱子是辅助作用,我们取 n = 1, n = 2, n = 3,进行简单分析推到:
当 n = 1时,直接将 A 上盘子移动到 C 柱子上,只需要1步;
当 n = 2时,将 A 最上的一个移动到 B 柱子上,再将 A 下面的盘子移动到 C 柱子上,最后将 B 柱子上的盘子移动到 C 上,共需要3步;
当 n = 3时,详细说明 n = 3的情况:
A)将A上的n-1(等于2,令其为n`)个圆盘移到B(借助于C),步骤如下:
(1)将A上的n`-1(等于1)个圆盘移到C上。 (2)将A上的一个圆盘移到B。 (3)将C上的n`-1(等于1)个圆盘移到B。
B)将A上的一个圆盘移到C。
C) 将B上的n-1(等于2,令其为n`)个圆盘移到C(借助A),步骤如下:
(1)将B上的n`-1(等于1)个圆盘移到A。 (2)将B上的一个盘子移到C。 (3)将A上的n`-1(等于1)个圆盘移到C。到此,完成了三个圆盘的移动过程。
从上面分析可以看出,当n大于等于2时,移动的过程可分解为三个步骤:第一步把A上的n-1个圆盘移到B上;第二步把A上的一个圆盘移到C上;第三步把B上的n-1个圆 盘移到C上;其中第一步和第三步是类同的。当n=3时,第一步和第三步又分解为类同的三步,即把n`-1个圆盘从一个针移到另一个针上,这里的n`=n-1。由于初始条件 n = 1,n = 2时均成立,故对于任意 n 递推形式也成立。
下面是Java代码实现:
public class Hanoi {
final static char A = 1; //设置3个字符标记3根柱子,只是标记作用,实际计算中用不到。
final static char B = 2;
final static char C = 3;
static int moveCount = 0; //用于记录总共移动的次数
public static void move(int n, char A, char B, char C) {
if (n > 1) {
move(n - 1, A, C, B); //将 n - 1 个盘子从 A 移动到 B 上
move(n - 1, B, C, A); //将 n - 1 个盘子从 B 移动到 C 上
}
moveCount++;
}
public static void main(String[] args) throws Exception {
move(7, A, B, C);
System.out.println(moveCount);
}
}
结果:
127