1.问题描述
汉诺塔问题是一个古典的数学问题,它只能用递归方法来解决。在古代有一个梵塔,塔内有A、B、C三个座。开始时A座上有64个盘子,盘子大小不同,但保证大的在下小的在上。现在有一个和尚想将这64个盘子从A座移动到C座,但他每次只能移动一个盘子,且在移动过程中在3个座上都必须保持大盘在下小盘在上的状态。在移动过程中可以利用B座,要求编程将移动步骤打印出来。
2.问题分析
具体步骤如下。
(1)将A座最上面的63个盘子移动到B座上。
(2)将A座上剩下的一个盘子移动到C座上。
(3)将B座上的63个盘子移动到C座上。
如果能完成上述3步,则任务完成。这种思考方法就是递归的思考方法。但实际上问为了解决将A座最上面的63个盘子移动到B座上的问题,还需要做如下工作。
(1)将A座上面的62个盘子移动到C座上。
(2)将A座上剩下的一个盘子移动到B座上。
(3)将C座上的62个盘子移动到B座上。
将这个过程进行下去,即不断的递归,继续完成移动62个盘子、61个盘子·····工作,直到最后将达到仅有一个盘子的情形,则将一个盘子从一个座移动到另一个座,问题也就全部得到了解决,所有的步骤都是可执行的。
要说明的是,只有移动一个盘子的任务完成后,移动两个盘子的任务才能完成,依次类推,只有移动63个盘子的任务完成后,移动64个盘子的任务才能完成,由此可知该问题是非常典型的递归问题。
3.算法设计
该问题使用递归算法来解决。由于递归算法具有如下的特征:为了求解规模为N的问题,应先设法将该问题分解成一些规模较小的问题,从这些较小问题的解可以方便地构造出大问题的解。同时,这些规模较小的问题也可以采用同样的方法分解成规模更小的问题,并能从这些规模更小的问题的解中构造出规模较小问题的解。特别地,当N=1时,可直接获得问题的解。
现在给出解决问题的方法。
先定义递归函数hanio(int N,char A,char B,char C),该函数表示将N个盘子从A座借助B座移动到C座,盘子的初始个数为N.下面是解题步骤:
若A座上只有一个盘子,此时N=1,则可直接将盘子从A座移动到C座上,问题解决。
若A座上有一个以上的盘子,即N>1,此时需要再考虑三个步骤。
(1)将N-1个盘子从A座借助C座先移动到B座上。显然,这N-1个盘子不能作为一个整体移动,而是要按照要求来移动。此时,可递归调用方法hanio(N-1,A,C,B),需要注意的是,这里是借助C座将N-1个盘子从A座移动到B座,A是源,B是目标。
(2)将A座上剩下的第N个盘子移动到C座上。
(3)将B座上的N-1个盘子借助于A座移动到C座上。此时,递归调用方法 hanio(N-1,B,A,C),此时,借助A座,将N-1个盘子从B座移动到C座。
完成了这3步,就可以实现预期的效果,在C座上正确地按次序叠放好所有的盘子。
4.完整程序
#include <stdio.h>
void hanoi(int n,char A,char B,char C)
{
if(n==1)
{
printf("Move dish %d from %c to %c\n",n,A,C);
}
else
{
hanoi(n-1,A,C,B);
printf("Move dish %d from %c to %c\n",n,A,C);
hanoi(n-1,B,A,C);
}
}
int main(void)
{
int n;
scanf("%d",&n);
hanoi(n,'A','B','C');
return 0;
}
5.运行结果