hanoi塔问题解析(二)

目录(?)[+]

在上一篇文章中解释了一下hanoi塔的基本过程和以及路径的打印! 
在这片文章中我们主要的说一下当前运行到得状态时第几个最佳状态! 
在解决上面的问题之间我们还要解决的就是hanoi塔移动的最小步数

hanoi塔移动的最小步数

我们之后hanoi塔移动的三个步骤: 
1. 将A柱子上面的三个移动到B柱子上面(借助C柱子) 
2. 将A柱子上面中最下面的圆盘移动到C柱子上面 
3. 将B柱子上面的所有圆盘移动到C柱子上面(借助A柱子) 
所以有下面的一个等式s(n)=1+1+s(n)=步骤1的总数+1+步骤三的总数 
不难知道第一个步骤和第二个步骤的移动数量是相同的! 
所以 
s(i)=s(i1)+1+s(i1)s(i)=s(i−1)+1+s(i−1) 
s(i)+1=2(s(i1)+1)s(i)+1=2(s(i−1)+1) 
a(i)a(i)代替s(i)s(i)a(i1)a(i−1)代替s(i1)s(i−1) 
我们得到下面的等式 
a(i)=2a(i1)a(i)=2∗a(i−1) 
因为s(1)==1s(1)==1,s(1)+1==2s(1)+1==2,所以a(1)==2a(1)==2
根据等比数列求和公式得到a(i)=2ia(i)=2i 
那么s(i)=2i1s(i)=2i−1

问题描述

给定一个整型数组arr,其中含有1、2和3,代表所有圆盘的目前状态,1代表 左柱,2代表中间柱子,3代表右柱子,arr[i]的值表示i+1个圆盘的位置。比如,arr={3,3,2,1},代表的是第一个圆盘在右柱子上,第二个圆盘在右柱子上,第三个圆盘在中间的柱子上,第四个柱子在左柱上。如果arr代表的状态时最优移动轨迹中出现的状态,要求返回arr这种状态是最优移动轨迹中的第几个状态。如果arr代表的不是最优一定状态,那么返回-1

举个例子: 
- arr=[1,1]。表示两个圆盘都在左边的柱子上面也就是初始状态,这个状态返回0 
- arr=[2,1]。表示第一个圆盘在中间的柱子上,第二个圆盘在左边的柱子上,这种情况是两个圆盘的hanoi塔游戏中最优移动轨迹的第一步,所以返回值为1 
- arr=[3,3]。俩个圆盘都在右边的柱子上,这种情况是两个圆盘的hanoi塔游戏中最优移动轨迹的最后一步,返回值为3 
- arr=[2,2]。两个圆盘都在中间的柱子上面,在最优的转移状态中不会这种情况,所以返回-1

对于arr数组来讲,arr[N-1]代表的是最大圆盘 N在哪个柱子上面,情况有下面的三种: 
* 圆盘NN在左边的柱子上,表示步骤1的完成情况未定,需要继续通过了解N1N−1个圆盘的状况才能知道! 
* 圆盘NN在右柱子上,表示步骤1已经完成,起码走了2N112N−1−1步,步骤2也已经完成,起码又移动了一步,所以当前状况起码的最优步骤为2N12N−1,剩下的步骤还要通过N1N−1个圆盘的状况开决定 
* 圆盘N在中柱上,这是不可能的,所以返回-1 
所以整个过程可以总结为:对于圆盘1~N来说,如果目标为A到C,那么有三种情况: 
1. 圆盘NN在A上面,需要考察1~N-1的情况,圆盘1~N-1的目标位从A到B 
2. 圆盘NN在C上面,起码走完了2N12N−1步,剩下的还要继续考察1~N-1的状况,圆盘1~N-1的目标从mid到to 
3. 如果圆盘在mid上面,直接返回-1 
递归形式的代码如下:

int step(int i,int from,int mid,int to)
{
    if(i==-1)return 0;
    if(ans[i]==mid) return -1;
    if(ans[i]==from) return step(i-1,from,to,mid);
    else {
        int res = step(i-1,mid,from,to);
        if(res==-1) return -1;
        return (1<<i)+res;
    }
}

这样最多是进入NN次递归,所以时间复杂度是o(n)o(n),但是因为递归函数需要函数栈的原因,这个程序的额外空间复杂度也是o(n)o(n),如果不用递归的话那么就能把额外空间降到o(1)o(1)

int step2(int i)
{
    int from=1,mid=2,to=3;
    int res =0;
    while((i--)>=0) {
        if(ans[i]==mid) {
            return -1;
        }
        if(ans[i]==to) {
             res+=(1<<i);
             swap(mid,from);
        }else swap(mid,to);
    }
    return res;
}

hanoi塔全部代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MX= 65;
int ans[MX];
void hanoi(int n,char A,char B,char C)
{
    if(n<=1) {
        printf("1 move %c to %c\n",A,C);
        return ;
    }
    hanoi(n-1,A,C,B);
    printf("%d move %c to %c \n",n,A,C);
    hanoi(n-1,B,A,C);
}
int step(int i,int from,int mid,int to)
{
    if(i==-1)return 0;
    if(ans[i]==mid) return -1;
    if(ans[i]==from) return step(i-1,from,to,mid);
    else {
        int res = step(i-1,mid,from,to);
        if(res==-1) return -1;
        return (1<<i)+res;
    }
}
int step2(int i)
{
    int from=1,mid=2,to=3;
    int res =0;
    while((i--)>=0) {
        if(ans[i]==mid) {
            return -1;
        }
        if(ans[i]==to) {
             res+=(1<<i);
             swap(mid,from);
        }else swap(mid,to);
    }
    return res;
}
int main(void)
{
    freopen("in.txt","r",stdin);
    int N;cin>>N;
    hanoi(N,'A','B','C');
    for(int i=0;i<N;i++) cin>>ans[i];
    cout<<step(N-1,1,2,3)<<endl;
    cout<<step2(N-1)<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值