经典汉诺塔问题是什么?
废话不多逼逼,看题:
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
先自己思考一小会,看看有没有想法,然后再看我逼逼
分析阶段
- 首先看看百度的解释:
分析:对于这样一个问题,任何人都不可能直接写出移动盘子的每一步,但我们可以利用下面的方法来解决。设移动盘子数为n,为了将这n个盘子从A杆移动到C杆,可以做以下三步:
(1)以C盘为中介,从A杆将1至n-1号盘移至B杆;
(2)将A杆中剩下的第n号盘移至C杆;
(3)以A杆为中介;从B杆将1至n-1号盘移至C杆。 [2]
这样问题解决了,但实际操作中,只有第二步可直接完成,而第一、三步又成为移动的新问题。以上操作的实质是把移动n个盘子的问题转化为移动n-1个盘,那一、三步如何解决?事实上,上述方法设盘子数为n, n可为任意数,该法同样适用于移动n-1个盘。因此,依据上法,可解决n -1个盘子从A杆移到B杆(第一步)或从B杆移到C杆(第三步)问题。现在,问题由移动n个盘子的操作转化为移动n-2个盘子的操作。依据该原理,层层递推,即可将原问题转化为解决移动n -2、n -3… … 3、2,直到移动1个盘的操作,而移动一个盘的操作是可以直接完成的。至此,我们的任务算作是真正完成了。而这种由繁化简,用简单的问题和已知的操作运算来解决复杂问题的方法,就是递归法。在计算机设计语言中,用递归法编写的程序就是递归程序。
- 看看我的理解:
在这里我们假设A杆上有3个盘,并且叫一个和尚去完成搬盘任务:从上面移动过程可以看出,只有A3的任务完成后,A2的任务才能完成,只有第2个小和尚到第3个小和尚完成后,第1个小和尚A1的任务才能完成。只有第1个小和尚A1的任务完成,才能完成他的任务。由此可见,整个过程是一个典型的递归问题。接下来我们来分析一下。
第1个小和尚命令:
①第2个小和尚先把第一根柱子的前两个盘子移动到第二根柱子,借助第三根柱子;
②第1个小和尚自己把第一根柱子最后的盘子移动到第三根柱子;
③第2个小和尚把前两个盘子从第二根柱子移动到第三根柱子。
显然,步骤②很容易实现。
其中在步骤①中,第2个小和尚需要移动两个盘子,他就命令:
a)第3个小和尚把第一根柱子的第1个盘子移动到第三根柱子(借助第二根柱子
b)第2个小和尚自己把第一根柱子的第2个盘子移动到第二根柱子上;
c)第3个小和尚把第1个盘子从第三根柱子移动到第二根柱子。
同样,这里的第b)步很容易实现,但第3个小和尚只需要移动1个盘子,所以他也不用再下派任务了(这也是停止递归的条件,也叫递归出口)
- 稍微抽象一点的理解:
上面的三根杆从左到右A、B、C,我们可以重新取个名字:from(从哪里开始)、temp(中转站)、dest(目的地):
开始分析:
只有一个盘子时:直接从from(A)移到dest(C )处
三个盘子时:1.将前两个盘子从from移到temp出,借助dest 2.然后将最后一个盘子从from直接移到dest处 3.现在temp处有两个盘子,而from处没有、dest有一个大盘子,这里我们可以将dest也看成是没有盘子,因为一个底座大盘子最终就是要放在dest处的。4.思维调换一下:将temp想成from 原本的from想成temp,这样又回到最开始的时候,我们不断这样递归下去就可以完成任务了。
看看代码
- Java老大哥:
package suanFa;
import java.util.Scanner;
/**
* “汉诺塔”问题
* @author 作者公众号:放牛娃学编程
*
*/
public class HanNuoTa {
// 移动函数
public static void hanNuo(int n, char from, char temp, char dest)
{
if(n == 1)
{
System.out.println(from+"------>"+dest);
}
else
{
hanNuo(n - 1, from, dest, temp);
System.out.println(from+"------>"+dest);
hanNuo(n - 1, temp, from, dest);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
long start = System.currentTimeMillis();
System.out.println("用A B C来模拟寺庙的三根柱子");
System.out.println("请输入碟子数目");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
System.out.println("以下是我的移动顺序哟!不信你就验算一下啦啦");
hanNuo(num, 'A', 'B', 'C');
long end = System.currentTimeMillis();
System.out.println("你好,上面的盘子我搬了"+((end - start)/1000)+"秒");
}
}
运行结果:
- Python新竞大哥
"""汉诺塔问题"""
import time
#移动函数
def hanNuoTa(n, froom, temp, dest):
if(n == 1):
print("%c----->%c" %(froom, dest))
else:
hanNuoTa(n - 1, froom, dest, temp)
print("%c----->%c" %(froom,dest))
hanNuoTa(n - 1, temp, froom, dest)
if __name__ == "__main__":
start_time = time.time()
print("用A B C来模拟寺庙的三根柱子")
number = int(input("请输入碟子数目"))
print("以下是我的移动顺序哟!不信你就验算一下啦啦")
hanNuoTa(number, "A", "B", "C")
end_time = time.time()
total_time = end_time - start_time
print("你好,上面的盘子我搬了%d秒" %total_time)
运行结果:
最后有兴趣一起交流的,可以关注我的公众号:这里你能够学到很实用的技巧,不是常用的我不说,年底还会抽奖送出我学过计算机相关专业的书籍福利。敬请期待!!!!