汉诺塔问题
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如图1)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
——来自于百度百科
编程要求
- 有A、B、C三根柱子,A为起始柱,B为辅助柱,C为目标柱,还有若干圆盘,圆盘按上小下大的顺序堆放在A柱上,从上到下依次为每一个圆盘标号为 1 到 n
- 输入圆盘数,要求将A柱的圆盘移动到C柱,一次只能移动一个,但是要保证不能把大圆盘放在小圆盘上面
- 输出每一个圆盘每一步移动的过程,比如:1号圆盘从 A -> C
- 提示:利用递归解决
解题思路
从宏观的角度思考问题,不要试图去理解每一个圆盘的移动过程
首先,如果只有一个圆盘,那么就可以直接移动到目标柱子上,无需借助辅助柱,这一点就可以作为递归函数的终止条件
如果圆盘数量 n >= 2的时候,可以分3步考虑:
1.把n上面的所有圆盘移动到B柱,C作为辅助,此时A是起始柱,B是目标柱,C只是作为辅助柱
2.把最大的圆盘n直接从A移动到C柱
3.把B柱上的圆盘全部移到C柱,A作为辅助,此时B是起始柱,C是目标柱,A只是作为辅助柱
从宏观角度来看就是这3步,不需要去考虑n以外的圆盘怎么移动,因为每进入一次递归,起始柱、目标柱和辅助柱都会变化,我们很难分清每一步是从哪个柱子到哪个柱子的
那么n-1个圆盘的移动交给递归方法去解决即可,因此我们仅需要写出终止条件时的移动以及 n>=2时的3个步骤即可
宏观图示如下:
我们就可以利用递归来实现这段代码
我们首先需要定义一个方法
方法的功能是:传入n个圆盘,就能根据汉诺塔的规则,把目标盘子从 a -> c, b是辅助柱
在写递归的时候,我们只需要想着如何调用他来实现上述功能就好了,剩下的交给程序
代码实现
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入圆盘的数量");
int num = in.nextInt();
hanoi(num, 'A', 'B', 'C');//最开始以A、B、C分别作为起始、辅助、目标柱
}
//汉诺塔方法实现
public static void hanoi(int num, char a, char b, char c){
//只有移动一个圆盘时
if (num == 1) {
//不需要经过b,直接从a -> c
System.out.println("第" + num + "个圆盘从" + a + " -> " + c);
}else{
//n >= 2时,核心步骤1:把上面的num-1个圆盘从a -> b,c作为辅助
hanoi(num - 1, a, c, b);
//核心步骤2:此时a上就剩下第num个圆盘,直接从a -> c
System.out.println("第" + num + "个圆盘从" + a + " -> " + c);
//核心步骤3:此时再把b上的这n-1个圆盘从b -> c,a作为辅助
hanoi(num - 1, b, a, c);
}
}
}
//执行结果
请输入圆盘的数量
3
第1个圆盘从A -> C
第2个圆盘从A -> B
第1个圆盘从C -> B
第3个圆盘从A -> C
第1个圆盘从B -> A
第2个圆盘从B -> C
第1个圆盘从A -> C
总结
汉诺塔问题的代码,一定要从宏观角度去研究问题,如果从微观角度去看,研究每一个圆盘是如何移动,很难理解。其次,多用画图来帮助自己理解问题!!