汉诺塔(整理)

Hanoi Tower问题其实是印度的一个古老的传说。开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。计算结果非常恐怖(移v动圆片的次数)18446744073709551615,众僧们即便是耗尽毕生精力也不可能完成金片的移动了。下面是有关汉诺塔的一些题目

1)====================  我 是 分 割 线 =======================

题目:将A棒上的金片全部移到C棒上

思想:

其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n – 1(有
兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了。 
  首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;若n为奇数,按顺时针方向依次摆放 A C B。 

(1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。 
(2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。 
(3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。 所以结果非常简单,就是按照移动规则向一个方向移动金片: 如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C 

就以Hanoi(4,1,2,3)举例来说:1、2、3分别代表可以存放盘子的底座的编号,4表示刚开始时第1个底座有4个盘子,a、b、c分别代表:问题开始时的原来存放盘子的底座、临时底座、问题结束时盘子存放的底座。那么怎么将第1个底座上4个盘子移动到第3个底座上呢? 按照上面的模型,分成三步:

(1)将第1个底座的最上面的3个盘子移动到第2个底座上;

(2)将第1个底座上剩下的1个盘子直接放到第3个底座上;

(3)将第2个底座上的3个盘子移动到第三个底座上;

上面三个过程实际上就对应到你的Hanoi(...)函数的中的三个语句。 第(1)、(3)步就是相当于原来问题的两个变形。可以把第(1)步理解为:将n-1个盘子从第1个底座搬到第2个底座的汉诺塔问题,这样问题有3个变化的地方和1个不变的地方:盘子总数减少了1、要将盘子移动到的目标底座变成了第2个底座了、临时底座变成了第3个底座了、问题的本质上还是汉诺塔问题,这个不变很重要,它是问题可以递归求解的关键,也就是说可以用不同的参数来调用同一个函数来解决。对应到Hanoi(...)函数的4个参数中的3个变化。 完成了前面两步后,显然问题并没有解决,所以才有第(3)步,也就是第二个递归。同样的道理第(3)步可以理解为:将n-1个盘子从第2个底座搬到第三个底座的汉诺塔问题了。只不过与第一个递归不同的是:原来的第2个底座相当于原来的第1个底座、原来的第1个底座相当于现在的第2个底座了。 补充:对于初学者来说,求解汉诺塔问题的方法其实很简单,但是求解的细节却很绕人,1、2、3与a、b、c的关系就不太好理解。个人认为搞清楚形式参数与实际参数的关系会对理解程序代码有帮助。直观的来看,123就是实际参数,abc就是形式参数。由前面内容可以看出,其实123和abc的意义在每一层递归调用中的含义是不同的,但就Hanoi(int n,int a,int b,int c)而言,每次调用它都是把当前要移动的盘子总数传给n、盘子初始位置传给a、目标位置传给c。进入Hanoi函数内部以后,问题被分解为“三步走”这样abc的具体含义在递归调用时就变化了。

实现:

public class Hanoi {
	public static void main(String[] args) {
		Hanoi h = new Hanoi();
		h.tower("A", "B", "C", 5);
	}

	public void tower(String fromTower, String toTower, String auxTower, int n) {
		if (n == 1) {
			System.out.println("Move disk 1 from tower " + fromTower
					+ " to tower " + toTower);
		} else {
			tower(fromTower, auxTower, toTower, n - 1);

			System.out.println("Move disk " + n + " from tower " + fromTower
					+ " to tower " + toTower);
			tower(auxTower, toTower, fromTower, n - 1);
		}
	}
}

  

计划、执行、每天高效的活着学着
原文地址:https://www.cnblogs.com/huxiaoyun90/p/3317277.html