汉诺塔(Towers of Hanoi)问题来自一个古老的传说:在世界刚被创建的时候有一座钻石宝塔(塔1),其上有64个金碟(如图5-4所示)。所有碟子按从大到小的次序从塔底堆放至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔 2和塔3)。从世界创始之日起,婆罗门的牧师们就一直在试图把塔1上的碟子移动到塔2上去,其间借助于塔 3的帮助。由于碟子非常重,因此,每次只能移动一个碟子。另外,任何时候都不能把一个碟子放在比它小的碟子上面。按照这个传说, 当牧师们完成他们的任务之后,世界末日也就到了。
在汉诺塔问题中,已知 n个碟子和3座塔。初始时所有的碟子按从大到小次序从塔1的底部 堆放至顶部,我们需要把碟子都移动到塔2,每次移动一个碟子,而且任何时候都不能把大碟子放到小碟子的上面。在继续往下阅读之前,可以先尝试对 n=2,3和4来解决这个问题。
一个非常优雅的解决办法是使用递归。为了把最大的碟子移动到塔2,必须把其余n-1个碟 子移动到塔3,然后把最大的碟子移动到塔2。接下来是把塔3上的n-1个碟子移动到塔 2,为此可以利用塔2和塔1。可以完全忽视塔2上已经有一个碟子的事实,因为这个碟子比塔3上将要移 过来的任一个碟子都大,因此,可以在它上面堆放任何碟子。
可以得到碟子的移动次数moves (n)如下:
得到的结果应为moves (n)=2n-1,函数的复杂性为 (2n )。
代码实现:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <stack>
using namespace std;
stack<int> s[4];
//从init_T移动n个碟子到end_T,使用temp_T作为碟子的中间存储
void Hanoi(int n,int init_T,
int end_T,int temp_T)
{
//停止条件:移动一个碟子
if (n==1)
{
s[init_T].pop();
s[end_T].push(n);
cout<<"move dish"<<n<<" frome "<<" T"<<init_T<<" to "
<<" T"<<end_T<<endl;
}
else
{
//从init_T到temp_T移动n-1个碟子,使用end_T进行临时存储
Hanoi(n-1,init_T,temp_T,end_T);
s[init_T].pop();
s[end_T].push(n);
//移动最大的碟子到end_T
cout<<"move dish"<<n<<" frome "<<" T"<<init_T<<" to "
<<" T"<<end_T<<endl;
//从temp_T到end_T移动n-1个碟子,使用init_T进行临时存储
Hanoi(n-1,temp_T,end_T,init_T);
}
}
//初始化
void InitHanoi(int n)
{
for (int d=n; d>0; d--)
{
s[1].push(d);//把碟子d 放到塔1上
}
Hanoi(n,1,2,3);
for (int i=1;i<=n;i++)
{
cout<<s[2].top()<<endl;
s[2].pop();
}
}
int main()
{
int n;
cout<<"Enter the number of dish: ";
cin>>n;
cout<<"The solution for n= "<<n<<endl;
InitHanoi(n);
return 0;
}