您的位置:首页 > 其它

汉诺塔问题

2017-10-23 14:01 274 查看

该问题描述

大致上这种题,都是有3座塔。Left , mid ,right 这三个塔。假设Left塔有n个盘子,盘子是从1到n的,1放在2上面,2放在3上面,依次类推,小盘子不能放到大盘子下面,现在我们需要把所有的Left塔的盘子移动到最右边,现在求最优的移动轨迹

分析

如果,我们要把n个盘子移动到right,需要做三步。

1.我们需要先把 1~i-1的盘子先移动到mid

2.把第i个盘子从Left移动到right

3.最后把mid上的1~i-1个盘子移动到right上。

对于移动 i 个盘子移动到mid,我们交给递归做,当移动第n个盘子,它只有一个我们自己把它的轨迹打印出来即可。

对于移动盘子到中间我们也要细分以下,路过中间的情况分为四种,L-M,M-L,M-R,R-M。所以当有出现有中间的时候,我们不能直接移动。我们可以做三步。

1. 将1~i-1个盘子移动另一边

2. 将第i个盘子移动到mid

3. 将1~i-1个盘子再从另一边移动到目的地即可。

列题

对于传统的汉诺塔游戏我们做一个拓展,我们有从大到小放置的n个圆盘,开始时所有圆盘都放在左边的柱子上,按照汉诺塔游戏的要求我们要把所有的圆盘都移到右边的柱子上,请实现一个函数打印最优移动轨迹。

给定一个int n,表示有n个圆盘。请返回一个string数组,其中的元素依次为每次移动的描述。描述格式为: move from [left/mid/right] to [left/mid/right]。

测试样例:

输入:

1

输出:

move from left to right

代码

#include<iostream>
#include<string>
using namespace std;
void Hano(int num,std::string left,std::string mid,std::string right,vector<string> & v_son)
{
if(num<1)
return;
return _Hano(num,left,mid,right,left,right,v_son);
}
void _Hano(int num,std::string left,std::string mid,std::string right,std::string from ,std::string to,vector<string> & v_son)
{
if(num==1)
{
std::string temp("move from ");
temp+=from;
temp+=" to ";
temp+=to;
v_son.push_back(temp);
}
else
{
if(from.compare(mid)==0||to.compare(mid)==0)
{
std::string anthor = (from.compare(right)==0||to.compare(right)==0)?left:right;
_Hano(num-1,left,mid,right,from,anthor,v_son);
std::string temp("move from ");
temp+=from;
temp+=" to ";
temp+=to;
v_son.push_back(temp);
_Hano(num-1,left,mid,right,anthor,to,v_son);
}
else
{
_Hano(num-1,left,mid,right,from,mid,v_son);
_Hano(1,left,mid,right,from,to,v_son);
_Hano(num-1,left,mid,right,mid,to,v_so
cbb7
n);

}
}
}
vector<string> getSolution(int n) {
// write code here
std::string left("left");
std::string right("right");
std::string mid("mid");
vector<string> v_son;
int num=n;
Hano(num,left,mid,right,v_son);
return v_son;
}
};


列题2

在第一题的基础上增加难度,现在不能直接从左边到右边或者从右边到左边。必须经过中间。当塔有N层的时候,打印最优路径和统计走过的步数。

分析

现在我们要移动1~i 个盘子从Left去Right,不能直接去了。所以分为以下几步:

1.移动1~i-1从Left到Right,交给递归过程

2.移动第 i 号盘子到mid

3.把1~i-1从Right移动到Left

4.把第i号盘子从mid移动到Right

5.把1~i-1从Left移动到right.

路过中间也要细分,不过处理跟上面的一样

代码

int _hanoiProblem(int num, std::string left, std::string mid, std::string right, std::string from, std::string to) //时间复杂度 n^3
{
if (num == 1)
{
if (from.compare(mid) == 0||to.compare(mid))
{
cout << "move 1" <<" " << from << " "  <<"to" <<" "<< mid<<endl;
return 1;
}
else
{
cout << "move 1" << " "<<from <<" "<<"to" <<" " <<mid<<endl;
cout << "move 1" <<" " <<mid <<" " <<"to" <<" " <<to<<endl;
return 2;
}
}
else
{
if (from.compare(mid) == 0 || to.compare(mid) == 0)
{
string anthor = (from.compare(right) == 0 || from.compare(right) == 0) ? left : right;
int step1=_hanoiProblem(num - 1, left, mid, right, from, anthor);
int step2 = 1;
cout << "move " << num << " " << "from" << " " << from << "to"<<" " << to << endl;//_hanoiProblem(1, left, mid, right, from, to);
int step3=_hanoiProblem(num - 1, left, mid, right, anthor, to);
return step1+step2+step3;
}
else
{
int step1=_hanoiProblem(num - 1, left, mid, right, from, to);
int step2 = 1;
cout << "move " << num << " "<<"from " <<" " <<from << "to"<<" " << mid<<endl;//_hanoiProblem(1, left, mid, right, from, mid);
int step3=_hanoiProblem(num - 1, left, mid, right, to, from);
int step4 = 1;
cout << "move " << num <<" "<<"from " <<" " <<mid << "to" <<" "<<to<<endl;
int step5=_hanoiProblem(num - 1, left, mid, right, from, to);
return step1+step2+step3+step4+step5;
}
}
}
int hanoiProblem(int num, std::string left, std::string mid, std::string right)
{
if (num < 1)
return 0;
return _hanoiProblem(num, left, mid, right, left, right);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: