汉诺塔问题
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); }