Hanoi塔问题(经典数学问题+递归)

问题描述:

这个问题起源于一个类似传说故事,在Hanoi这个地方有一个寺庙,这里有3根柱子和64个大小不同的金碟子。每个碟子有一个孔可以穿过。所有的碟子都放在第一个柱子上,而且按照从上到下碟子的大小依次增大的顺序摆设。如下图:

    现在,假定寺庙里的僧侣要移动这些碟子,将它们从最左边移动到最右边的柱子上。不过移动的规则如下:

1. 每次只能从一个柱子的最上面移动一个碟子到另外一个柱子上。

2. 不能将大碟子放到小碟子的上面。

    按照前面这个规则,我们该怎么去移动这些碟子呢?假定单位时间内可以移动一片碟子,那么最终移动这些碟子到目的柱子需要多长的时间呢?

 问题分析:

在分析这个问题的时候,我们可以先从一些简单的场景来看怎么来移动碟子保证可以达到目的。假定我们有3个碟子,那么移动它们的过程如下图:

我们假定柱子从左到右分别为a, b, c。从前面移动碟子的步骤可以看到,我们要将a上面的两个碟子先移动到中间的b柱子作为过渡,然后再将最下面的柱子移动到目的c柱子,然后再将上面的两个碟子移过来。在将最下面的碟子移动到c之前,首先的步骤1, 2, 3是将上面的碟子移动到柱子b。而将最下面碟子移动后,上面的两个碟子又要移动一遍,不过是从b移动到c,只是借助的柱子不一样。

 所以,从上面的过程,我们可以看到一个可以递归解决问题的思路,如下图:

 

如图所示,首先我们针对有n个碟子的柱子a,将n-1个碟子移动到柱子b。假定这个问题为S(n)表示移动的步数,则上面的问题是S(n)的一个子问题S(n-1)。这一步对应步骤1。然后将最下面的碟子移动到柱子c,最后再将n-1个碟子移动到c。后面这一步也相当于S(n)的子问题S(n-1)。对应步骤3.它和前面第一步移动n-1个碟子唯一不同的地方在于第一步是借助c将n-1个碟子从a移动到b,而最后这一步是借助a将n-1个碟子从b移动到c。除了借助的柱子和目的柱子不一样,其他都是一样的。

 代码实现:

前面的分析可以发现,从计算机实现来说,这个问题是指数函数级别的,意味着它的增长速度非常快,在一定程度上计算机都无法解决。在一个比较小的数值范围内,我们还是可以做一个参考实现的,这部分代码里,我们递归的退出条件是当最终碟子移走,即n == 0。有了前面的讨论,我们的完整代码实现如下: 

C/C++版本: 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
void Hanoi(int n,char a,char b,char c)
{
	if(n==0)
		return ;
	Hanoi(n-1,a,c,b);
	printf("Move disk %d from %c to %c\n",n,a,c);
	Hanoi(n-1,b,c,a);
}
int main()
{
	int n;
	scanf("%d",&n);
	Hanoi(n,'a','b','c');
	return 0;
}

 Java版本:

import java.util.*;
public class Main
{
	public static void move(int n,char a,char b,char c)
	{
		if(n==0)
			return ;
		move(n-1,a,c,b);
		System.out.printf("Move disk %d from %c to %c\n",n,a,c);
		move(n-1,b,c,a);
	}
	public static void main(String[] args)
	{
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		Main.move(n,'a','b','c');
	}
}
发布了274 篇原创文章 · 获赞 282 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43823808/article/details/104038733
今日推荐