汉诺塔(河内塔)


一、 河内塔的起源


1883年,一位法国的数学家Edouard Lucas 教授在欧洲的一份杂志上介绍了一个相当吸引人的难题──迷人的智力游戏。 这个游戏名为河内塔(Tower of Hanoi),它源自古印度神庙中的一段故事(也有一说是Lucas 教授为增加此游戏之神秘色彩而捏造的)。 传说在古老的印度,有一座神庙,据说它是宇宙的中心。 在庙宇中放置了一块上面插有三根长木钉的木板,在其中的一根木钉上,从上至下被放置了64片直径由小至大的圆环形金属片。 古印度教的天神指示祂的僧侣们将64片的金属片移至三根木钉中的其中一根上。 规定在每次的移动中,只能搬移一片金属片,并且在过程中必须保持金属片由上至下是直径由小至大的次序,也就是说不论在那一根木钉上,圆环形的金属片都是直径较小的被放在上层。 直到有一天,僧侣们能将64片的金属片依规则从指定的木钉上全部移动至另一根木钉上,那么,世界末日即随之来到,世间的一切终将被毁灭,万物都将至极乐世界。

倘若这个故事的叙述为真,那么,我们只需加速移动金属片,是不是就能愈早到达极乐世界呢? 果真要移动这64片金属片,那么,至少要花几次的搬动才能完成呢? 有没有规律可循呢?

二、 河内塔的数学

对于河内塔游戏也可以经由数学上的方法得到一些漂亮的结果:若一开始就考虑64片金属片似乎太难了,我们不妨把金属片的数量降低至2片,看看会有什么结果?

如果只有1片,显然只须移动一次即可。 当2片直径不一的金属片放在同一木钉上,必须将最上的那一片先移至非指定的木钉上,然后将第二片金属片移至指定的木钉上,再接着将第一片金属片移至第二片之上,所以,至少要花3次搬移来完成。 若是3片金属片,依相同的讨论方法,可得知须至少移动金属片7次,如图1。



汉诺塔(河内塔)_第1张图片
                                                                                                             图 1


那当n很大时(金属片数= n ),至少要花几次呢?
      现在 假设至少须T(n) 次的移动来完成,那么,我们再加一片金属片,即此时共有n+1 片金属片;我们知道前n 片花了T(n) 次来移动至另一根木钉上,第n+1 片金属片只须花一次就可移至指定的木钉上,所以,只须再花T(n) 次的移动将n 片金属片移至这一片金属片之上,这就完成了任务──有n+1 片金属片移到另一根木钉上。 它们都是在规范内被完成移动,所以最少移动次数有如下迭代公式:

T(n+1) = 2T(n) + 1

又已知T(1) = 1, T(2) = 3, T(3) = 7 ,因此是否可以推出T(64)?
由迭代公式知道:
T(n+1) = 2T(n) + 1
T(n+1)+ 1 = 2T(n) + 2
T(n+1) + 1 = 2(T(n) + 1)

因此构造出以公比为2的等比数列,不难计算知道知道的公式为:



     所以我们可以计算出:

好了,河内塔的数学推导暂时到这里了,现在我们看看它何如在三个柱子之间移动的。

四、 河内塔移动方式

若将三根木钉排成一个三角形(即木钉在三角形的顶点)如图2。 假设,移动金属片的方式被分为顺时针方向及逆时针方向,每做一次顺时针方向移动,我们在纸上划上﹨,做一次逆时针方向则划上∕,若令出发点为A 柱,终点为C 柱。 逐步记录结果:


汉诺塔(河内塔)_第2张图片


    图 2

三片金属片移动的路径:
                     汉诺塔(河内塔)_第3张图片



5、汉诺塔移动路径实现算法(摘自百度百科,链接:http://baike.baidu.com/view/191666.htm#4_3)

   算法介绍

其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n – 1(有兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了。首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;
若n为奇数,按顺时针方向依次摆放 A C B。
⑴按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。
⑵接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。
⑶反复进行⑴⑵操作,最后就能按规定完成汉诺塔的移动。
所以结果非常简单,就是按照移动规则向一个方向移动金片:
如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C
现在我给出我自己写的C语言代码:
#include 

//A桩为初始位置,B为临时位置,C为目的位置,n为现在A桩上盘子的数目 
void Hanoi_towers(char A, char B, char C, int n) 
{
	if( n == 1)
		printf("%c===>%c\n", A, C);  /**
									  *因为在只有一片金属片时, 
									  *直接将A移动到C既可 */
	else{
		Hanoi_towers(A, C, B, n - 1); /**
									   *当金属片只有大于一片时,
		                               *借助B作临时存放A的位置 */
		printf("%c===>%c\n", A, C);   //因为移动了一次,则将其输出 
		Hanoi_towers(B, A, C, n - 1);  /**
										*因为借助了B为临时存放A,
										*最后要将其A归回原位*/
	} 
}

int main()
{
	Hanoi_towers('A','B','C',3);
	return 0;
}

内容参考源于:http://www.chiuchang.com.tw/toy/hanoi/hanoi.html

你可能感兴趣的:(排序算法学习)