56 汉诺塔问题的第m步
作者:
问题描述 :
给定三根杆A、B、C和大小不同的几个盘子。这些盘子按尺寸递减顺序套在A杆上,最小的在最上面。现在的任务是把这些盘子从A杆移到C杆且保持原来堆放顺序。在实现任务时,每次只能移动一个盘子,且任何时刻不允许大的盘子放在小的盘子上面,B杆可以作为辅助存放杆。求:总共有n个圆盘时,搬动过程中的第m步是从哪个杆到哪个杆。
输入说明 :
你的程序需要从标准输入设备(通常为键盘)中读入多组测试数据。每组输入数据由一行组成,每行输入一个整数表示盘子数n,1≤n≤10,以及步数m,两个数据之间以一个空格分隔。行首和行尾没有多余的空格,两组数据之间也没有多余的空行。
输出说明 :
对每组测试数据,你的程序需要向标准输出设备(通常为启动该程序的终端)依次输出一行对应的答案,该行中输出第m步移动的情况,如第m步是从A移到B,则输出“A--B”(不包括引号)。如果移动过程不存在第m步,则输出“none” (不包括引号)。
两组数据之间无空行,第一组前及最后一组后也无空行。
输入范例 :
2 3
2 4
输出范例 :
B--C
none
先来回顾下汉诺塔问题。讲真的,作为一个科班的CS学生,大二的时候一致没有搞懂汉诺塔问题,今天必须和它做一个了断。
我们先根据游戏规则,从最简单的情况分析一波:
图一 最简单的情况
第一种情况如图一所示,这种情况最简单了,按照游戏规则,我们可以直降将A上的盘子移动到C上面。问题得到解决(虽然这是最简单的问题,
但是这个问题是以后大问题的子问题)。
图二:两个盘子
第二种情况如图二所示:这个问题变得稍微复杂了一些,按照游戏规则,我们只能先移动1(不要忘了,我们是要把所有的盘子按照规则从A移动到C)。
为了使步数最少,我们先将盘子1移动到B(借助B),然后将大盘子2直接移动到C,最后再将B上的盘子1移动到C。问题得到解决。
图三:三个盘子的情况
第三种情况如图三所示,为了将三个盘子从A移动到C,我们要动些脑筋了。
当然了,我们可以用手模拟一下,如下(其实完全可以省略……,我们还是动手模拟下)
首先我们要达成一个共识,
A->B(将A上的1移动到B上)
A->C(将A上的2移动到C上)
C->B(将C上的1移动到B上)
A->C(将A上的1移动到C上)
图四
到这里我们可以先停下来看看我们做了些什么。
简单总结下来就是,我们想了一些办法,经过某种操作(不要怀疑你的做法),使得盘子1和2从A上移动到了B上,
然后我们可以将最大的盘子从A上直接移动到C上。问题似乎有了进展,但是还没有解决。我们下一步要解决的是
将盘子1和2移动到C上。
B->A(将B上的1移动到A上)
B->C(将B上的2移动到C上)
图5
此时,问题显然已经得到了解决。但是刚刚的感觉好像再重复着某些动作。是的,我们必须把重复的动作找出来。
是这样的,当A上有三个盘子的时候(图三),我们先是想办法将1和2移动到B上,然后将A上最大的盘子移动到C上。(图四)
接下来的问题就变成了将盘子1和2借助于A移动到C上,我们先是将1移动到A上,然后将B上剩下的最大的盘子2移动到了C上(图5)。
动作真的非常重复,我没有什么好的语言去总结,但是规律已经很明显了。
0、想办法将A上的盘子全部移动到C上面
1、首先将A上除了最大盘子以外的盘子移动到B上(借助B)
2、然后将A上最大的盘子直接移动到C上
3、想办法将B上的盘子全部移动到C上面(其实问题已经回到了0,变得只是规模和充当被借助的对象)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 #include <string.h> 5 #include <ctype.h> 6 7 #define maxn 1005 8 9 10 int n,m,step; 11 void Hanoi(int n,char x,char y,char z); 12 void move(char x,char y); 13 int main(){ 14 15 16 char x,y,z; 17 x = 'A'; 18 y = 'B'; 19 z = 'C'; 20 while(scanf("%d %d",&n,&m)!=EOF){ 21 step = 0; 22 Hanoi(n,x,y,z); 23 if(step<m||m<=0){ 24 printf("none\n"); 25 } 26 } 27 28 29 return 0; 30 } 31 32 void Hanoi(int n,char x,char y,char z){ 33 if(n == 1){ 34 //只需要移动一个盘子 35 step++; 36 move(x,z);//将变量x代表的柱子上的盘子从x移动到z所代表的柱子上z 37 return; 38 } 39 40 Hanoi(n-1,x,z,y);//首先将A上除了最大盘子以外的盘子移动到B上(借助C) 41 step++; 42 move(x,z);//将变量x代表的柱子上的盘子从x移动到z所代表的柱子上z 43 Hanoi(n-1,y,x,z); 44 } 45 46 void move(char x,char y){ 47 if(step == m){//只有在第m步中输出 48 printf("%c--%c\n",x,y); 49 } 50 }