汉诺塔的由来
这部分来自百度百科
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的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时,
假如每秒钟一次,共需18446744073709511615秒。
这表明移完这些金片需要5845.42亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.42亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。
移动方案
汉诺塔实际移动起来很费时,但作为新时代的少年,我们可以通过程序来求解每一步的移动策略。
本文所使用的方式是递归求解 从 A 移动到 C
的问题,我们先来整理下思路:从三种基本情况说起。
情况一:1pcs 从 A 移动到 C,B 做缓冲柱
只有一步,从 A 移动一片到 C
情况二:2pcs 从 A 移动到 C,B 做缓冲柱
需要:
- 从 A 移动一片到 B,用做缓冲
- 从 A 移动一片到 C
- 从 B 移动一片到 C
情况三:3pcs 从 A 移动到 C,B 做缓冲柱
需要:
- 1:从 A 移动一片到 C
- 2:从 A 移动一片到 B
- 3:从 C 移动一片到 B
- 4:从 A 移动一片到 C
- 5:从 B 移动一片到 A
- 6:从 B 移动一片到 C
- 7:从 A 移动一片到 C
当总片数达到3片时已经有些小复杂了,而我们通过上面的7个步骤可以发现:
- 步骤1,2,3是把A 柱顶部的2pcs,
从 A 移动到了 B,C 做缓冲柱
。 - 步骤4正常移动
- 步骤5,6,7是把 B 柱上的2pcs,
从 B 移动到 C,A 做缓冲柱
从特殊情况到一般
针对情况三的3pcs,我们可以这么总结:
- 假设目的是从 A 移动到 C,缓冲为 B
- S1:需要先将 A 除最底部的1pcs外的所有圆盘移动到 B 缓冲
- S2:再将 A 最后1pcs 移动到 C
- S3:最后再将 B 中的所有圆盘移动到 C
假设 移动的方法为 MOVE(pcs,start,end,buffer),当 pcs=n时:
- S1: MOVE(n-1,A,B,C)
- S2: MOVE(1,A,C,B)
- S3: MOVE(n-1,B,C,A)
S1可能存在的疑问
S1一次移动那么多盘子,怎么处理?
盘子这么多,我也不知道怎么处理。继续拆分吧,分治策略就是这样,拆分到可以解决为止。其实步骤S1在一共只有3pcs 的情况下只是从 A 移动到 B 2pcs,这种2pcs情况其实已经可以解决了不是?
源码
public class Hanoi {
public static void main(String[] args) {
move(3,"A","C","B");
}
private static void move(int pcs, String start, String end, String buffer) {
if (pcs == 1) {
System.out.println("从" + start + "移动一片到" + end);
} else if (pcs == 2) {
System.out.println("从" + start + "移动一片到" + buffer);
System.out.println("从" + start + "移动一片到" + end);
System.out.println("从" + buffer + "移动一片到" + end);
} else {
move(pcs - 1, start, buffer, end);
System.out.println("从" + start + "移动一片到" + end);
move(pcs - 1, buffer, end, start);
}
}
}