该问题描述
大致上这种题,都是有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_son);
}
}
}
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);
}