新汉诺塔

Description

设有n(n<=50)个大小不等的中空圆盘,按从小到大的顺序从1到n编号。将这n个圆盘任意的迭套在三根立柱上,立柱的编号分别为A、B、C,这个状态称为初始状态。

现在要求找到一种步数最少的移动方案,使得从初始状态转变为目标状态。

移动时有如下要求:

  • 一次只能移一个盘;
  • 不允许把大盘移到小盘上面。

Analysis

没有头绪的一题,如果圆盘有序放置,是不是题目会简单很多?答案是肯定的。

显而易见,每次只能移动顶层的圆盘,但是此思维类似于爆搜,是不可取的。回到汉诺塔游戏的思路,将n-1个盘子转移走,把自己放到目标杆子上,把n-1个盘子放回来,所以是一个递归的思想。

这题规则有所改变,每个盘子都有自己的目标状态。只能把目标状态中底部的盘子先达到目标,再把另外n-1个盘子弄上去。而瞄准一个盘子怎么把它放上去呢?

首先肯定要把目标点的盘子拾搬,把自己头上的拾搬,最后才能把自己放上去。这显然是正确的,但是拾搬的扔到哪呢?只能扔到另一根柱子上了。

接着,我就没有彻底没有头绪了,因为任意迭套存在小的上面有大环的情况,这个拾搬的策略实在是太复杂了。先写一个初始状态一定为有序的code试试看。

懵逼,竟然AC了。原来是我题目理解错了,放置的时候一定是有序的...

那么这个题目就比较简单了,每次把需要移动的最大的移动过去,为了给他腾出地方,把比他小的盘子中占据目标位置和在他头上的都扔另一个杆子上去,产生子问题。

Code

#include <bits/stdc++.h>
const int N=51;
const char M[3]={'A','B','C'};
int pole[N],tar[N],step;
void move(int x,int s,int t){
    if(t==s)return;
    for(int i=x-1;i;i--)
        if(pole[i]==t)move(i,t,3-s-t);
        else if(pole[i]==s)move(i,s,3-s-t);
    pole[x]=t;
    step++;
    printf("move %d from %c to %c\n",x,M[s],M[t]);
}
int main(){
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(int i=0;i<2;i++)
        for(int j=0;j<3;j++){
            int num,p;
            scanf("%d",&num);
            for(int k=1;k<=num;k++){
                scanf("%d",&p);
                if(!i)pole[p]=j;
                if(i)tar[p]=j;
            }
        }
    for(int i=n;i>=1;i--)
        move(i,pole[i],tar[i]);
    printf("%d\n",step);
    return 0;
}

转载于:https://www.cnblogs.com/qswx/p/9509245.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值