汉诺塔问题及其扩展 (4塔)

前几天上算法分析与设计课时,又提到了汉诺塔问题,所以我就在这里做一个总结。

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。

汉诺塔问题是一个非常典型的递归题目,相信大家也都很熟悉,我就不做过多解释了。

下面附上递归算法的步骤:

(1)     把n-1个盘子由A 移到 B;

(2)     把第n个盘子由 A移到 C;

(3)     把n-1个盘子由B 移到 C;

附上代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define cla(a, sum) memset(a, sum, sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=3e4;
int n,m;

void dfs(int n,char A,char B,char C)
{
	if(n==1){
		printf("第%d次移动 : 把 %d 号圆盘从 %c ->移到-> %c\n",++m,n,A,C);
		return ;
	}
	dfs(n-1,A,C,B);
	printf("第%d次移动 : 把 %d 号圆盘从 %c ->移到-> %c\n",++m,n,A,C);
	dfs(n-1,B,A,C);
}
int main()
{
	printf("输入盘子的个数: ");
	cin>>n;
	m=0;
	dfs(n,'A','B','C');
	printf("移动次数是: %d\n",m);
	return 0;
}

其实对于这个问题,用递归来解决 时间复杂度较高,但是多数几个样例,进行测试,你会发现,有一个规律。

即移动次数等于2^n-1 (不会推导,找的规律);

 

接下来说一下汉诺塔的扩展性问题,即四塔问题。

核心思想就是将A上的盘子看作两部分。

首先我们可以先考虑A柱子上面只有三个盘子的情况,对于A柱子上的三个盘子,我们可以先将一个盘子从A柱子移动到B柱子上面,再将第二个盘子移动到C柱子上面,最后将剩下的一个盘子移动到D柱子上面。其实对于这个过程,我们可以将其看成:首先将A柱子上面的盘子分成了两部分,第一部分上面只有一个盘子,第二部分有两个盘子,我们要做的就是先将第一部分的盘子移动到B(C也可以)柱子上面,然后将剩下的盘子移动到D柱子上面,在将B柱子上面的盘子移动到D柱子上面。

因此算法的主要的思路就是:
1,对于A柱子上面有n个盘子的时候,我们可以先将盘子分成k和n-k两个部分
2,将A柱子上面的K个盘子使用Hanoi4方法将其借助C,D柱子移动到B柱子上面
3,将A柱子上面剩下的n-k个盘子使用Hanoi3方法将其借助C柱子移动到D柱子上面
4,将B柱子上面的K个盘子使用Hanoi4方法将其移动到D柱子上面

思路来自:https://blog.csdn.net/Scorpion_CG/article/details/78161539

最近刚学java,附上个java代码:

package bag;

import java.util.Scanner;

public class hannuota4 {
	private static Scanner sc;
	static int m=0;
	public static void main(String args[])
	{
		sc = new Scanner(System.in);
		int n=sc.nextInt();
		char a='A',b='B',c='C',d='D';
		Hanoi(a,b,c,d,n);
		System.out.println(">>移动了" + m + "次,把A上的圆盘都移动到了C上");
	}
	private static void Hanoi(char a, char b, char c, char d, int n) {
		if(n==1)
			{
			System.out.println("将盘子从"+a+"柱子移动到"+d+"柱子");
			m++;
			return;
			}
			Hanoi(a,c,d,b,n/2);
			Hanoi3(a,b,c,d,n-n/2);
			Hanoi(b,c,a,d,n/2);			
	}
	private static void Hanoi3(char a, char b, char c, char d, int i) {
		if(i==1) {
			System.out.println("将盘子从"+a+"柱子移动到"+d+"柱子");
			m++;
		}
		else{
			Hanoi3(a, b, d, c, i-1);
			System.out.println("将盘子从"+a+"柱子移动到"+d+"柱子");
			m++;
			Hanoi3(c, a, b, d, i-1);
		}
	}
}

C++代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define cla(a, sum) memset(a, sum, sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=3e4;
int n,m;

void dfs(int n,char A,char B,char C)
{
	if(n==1){
		printf("第%d次移动 : 把圆盘从 %c ->移到-> %c\n",++m,A,C);
		return ;
	}
	dfs(n-1,A,C,B);
	printf("第%d次移动 : 把圆盘从 %c ->移到-> %c\n",++m,A,C);
	dfs(n-1,B,A,C);
}

void DFS(int n,char A,char B,char C,char D)
{
	if(n==1){
		printf("第%d次移动 : 把圆盘从 %c ->移到-> %c\n",++m,A,D);
		return ;
	}
	DFS(n/2,A,C,D,B);
	dfs(n-n/2,A,C,D);
	DFS(n/2,B,A,C,D); 
}
int main()
{
	printf("输入盘子的个数: ");
	cin>>n;
	m=0;
	DFS(n,'A','B','C','D');
	printf("移动次数是: %d\n",m);
	return 0;
}

 

附上一个找规律解决四塔问题的题解:https://www.cnblogs.com/guyahan/p/5439495.html

你可能感兴趣的:(数据结构,搜索)