汉诺塔问题

该问题描述

大致上这种题,都是有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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值