汉诺塔问题
传说印度古代有一个很有趣的游戏,当游戏结束的时候,世界便也毁灭了!
#include <stdio.h>
int main(){
void hanoi(int n,char one,char two,char three);
int m;
printf("input the number:");
scanf("%d",&m);
printf("total step is:\n",m);
hanoi(m,'A','B','C');
return 0;
}
void hanoi(int n,char one,char two,char three){
void move(char x,char y);
if(n==1)
move(one,three);
else
{
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
void move(char x,char y){
printf("%c--->%c\n",x,y);
}
以上是书上P188的代码。具体的方法如下:
假如有A、B、C三座塔。此时A座上有5(n)个盘子。
那么想把A座上的盘子移到C座上则需要三个步骤:
(1)将A座上的4(n-1)个盘子先借助C座移动到B座上。
(2)将A座剩下的1个盘子移动到C座上。
(3)将B座的4(n-1)个盘子借助A座移动到C座上。
因此,通过这三个步骤可以看出:
1、3两个步骤的移动都必须要通过除了目标底座和自己底座外的第三个底座才能将本座上的盘子移动到目标底座。
1、3两个步骤都可以分别再各自进行拆分成三个步骤。比如:
第1个步骤可拆分为:
(1)将A座上3个盘子借助B座移动到C座上
(2)将A座剩下的一个盘子移动到B座上
(3)将C座上的3个盘子借助A移动到B座上
而这三个步骤中的1、3两个步骤又可以各拆分成三个步骤,以此类推...直到A座上只剩下一个盘子了,则不需要借助任何底座,直接移动到目标底座。
目标底座的确定:每次移动到的目标底座是根据上一个步骤的目标而确定的。比如:第一次移动的目标是将A座上的4个盘子先借助C座移动到B座上,所以它拆分出来的步骤就是要想办法将4个盘子移动到B座上,怎么移呢?就要先将3个盘子借助B座移动到C座,而这个步骤又成了下一个拆分步骤的目标。
了解了这三个大步骤,再看代码就容易了。先看看他主要负责三大步骤的函数:
void hanoi(int n,char one,char two,char three){
void move(char x,char y);
if(n==1)
move(one,three); //这里并不是代表将A座盘子移动到C座,而是将A座盘子移动到拆分步骤到最后一步时,只有一个盘子时,应该将它先移到目标底座上的意思。
else
{
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
这里函数hanoi(one,two,three)这三个参数是形式参数,是虚拟的,并不是代表真实的三座塔。可以这样理解,这三个参数是one表示当前底座,two表示另外的一个底座,three表示目标底座的意思,但是并没有给出具体本座和目标和另外的一座是哪三座。而具体是哪三座,是根据传入的数值而决定的。
我们虽然不能确定在拆分中的具体是哪座底座上的盘子移到哪座底座上,但是我们能确定的是第一次的三大步骤。便是:先将A上N-1的盘子通过C移到B,再将A上的最后一个移到C,最后将B上的盘子通过A移到C。便是代码else中三句话的意思。所以,在进行每个步骤的具体拆分以后,就是再次调用hanoi函数后,one,two,three三个形式参数对应的值便不再是ABC了。而是具体拆分后新产生的本身底座,另一个底座和目标底座,也就是上面所解释的“目标底座的确定”。直到拆分到最后只剩下一个盘子了,便不再执行else,直接将此盘子从A移动到目标底座。
主要的函数意思懂了,剩下的就简单了。其中每次移动,就调用move(char x,char y)函数。move()函数的作用就是每次打印出移动的步骤。即从本底座(x)移动到目标底座(y)。
在主函数中就是给henoi()函数传参数,参数便是几层(调用自己几次)和开始时三座塔的顺序(A,B,C)。
运行结果:
input the number:3
total step is:
A--->C
A--->B
C--->B
A--->C
B--->A
B--->C
A--->C
已有 4 条评论
发表新评论
- 上一篇: C语言使用输入字符串函数时的问题
- 下一篇: C程序设计(第五版) 第六章 知识总结
警惕陷入二元对立思维,可尝试中间路径。
不错不错,我喜欢看
good
hf