一.题目简介
汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
二.问题分析
首先是三个石柱,我们假设其分别为A,B,C
我们现在假设有1个盘子
那我们肯定是将这个盘子直接从A柱移到C柱:
如果有两个盘子呢?
我们肯定是先将A柱最上面的一个盘子从A柱移动到B柱:
然后再将A柱上的盘子移动到C柱:
最后再将B柱上的盘子移动到C柱上,这样就满足要求了:
那么再复杂一点,3个盘子呢?
我们可以先将A柱上最上面的盘子移动到C柱上:
再将A柱上现在最上面的移动到B柱上:
然后将C柱上的盘子移动到B盘上:
然后再将A柱最底部的盘子移动到C柱上:
然后是将B柱最上面的盘子移动到A柱上,
再将B柱上的盘子移动到C柱上:
最后是将A柱上的盘子移动到C柱上:
不知道大家有没有发现,我们在移动盘子的过程中,都会将(n-1)个盘子移动到B柱上,然后将A柱上的第n个盘子移动到C柱上。
这个时候我们就可以将其推广到n个盘子的时候,这个时候的思路是 ,我们先将A柱上的(n-1)个盘子从A柱移动到B柱上:
再将A柱上的第n个盘子从A柱移动到C柱上:
然后我们再将B柱上的(n-2)个盘子从B柱移动到A柱上:
再将B柱上的第(n-1)个盘子从B柱移动到C柱上:
如此往复下去,直到n个盘子全部按照大小移到C柱上。
当我们分析到n个盘子的时候,就应该能意识到这是一个函数递归的问题,函数递归最主要就是大事化小思想,我们可以看到要实现n个盘子的移动时,我们其实是将其看成了两部分(第n个盘子和(n-1)个盘子),我们是将(n-1)个盘子看成一个整体,所以我们在处理n个盘子的移动时,简化成了2个盘子的移动,这样第n个盘子就很好移动到它该处的位置,然后再将剩余的(n-1)个盘子看成第n-1个盘子和(n-2)个盘子(同样是将(n-2)个盘子看成一个整体),就这样层层递归下去,将大事件化简成小事件处理。
三.代码实现
C语言代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
//汉诺塔问题
void move(char pos1, char pos2)
{
printf(" %c->%c ", pos1, pos2);
}
/*
N:有N个盘子
pos1:起始位置
pos2:中转位置
pos3:目标位置
这里我们假设有n个盘子,我们先将n-1个盘子从A上移到B上,
再将A上的第n个盘子从A移到C上,然后我们再将B上的n-2个
盘子从B上移到A上,再将B上的第n-1个盘子从B上移到C上,
如此往复下去,直到n个盘子全部按照大小移到C盘上
*/
void Hanoi(int N, char pos1, char pos2, char pos3)
{
if (N == 1)
{
move(pos1, pos3);
}
else
{
Hanoi(N - 1, pos1, pos3, pos2);
//现在盘子都在pos1上,现在通过中转位置pos3,将n-1个盘子移动到目标位置pos2上。
move(pos1, pos3);
//此时我们已将将n-1个盘子挪开了,只剩下第n个盘子了,直接将第n个盘子移动到目标盘即可。
Hanoi(N - 1, pos2, pos1, pos3);
//现在我们还有n-1个盘子需要挪动,现在我们的n-1个盘子在pos2上,
//我们需要通过中转位置pos1来将n-2个盘子移动到目标位置pos3.
}
}
#include<stdio.h>
int main()
{
int N = 0;
scanf("%d", &N);
Hanoi(N, 'A', 'B', 'C');
return 0;
}
Java代码实现:
import java.util.Scanner;
public class Text {
public static void main4(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
Hanoi(n,'A','B','C');
}
public static void Hanoi(int n,char pos1,char pos2,char pos3){
if(n==1){
move(pos1,pos3);
}else{
Hanoi(n-1,pos1,pos3,pos2);
move(pos1,pos3);
Hanoi(n-1,pos2,pos1,pos3);
}
}
public static void move(char pos1,char pos2){
System.out.println(pos1+"->"+pos2);
}
}