洛谷 P1242 新汉诺塔

题目描述

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

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

移动时有如下要求:

·一次只能移一个盘;

·不允许把大盘移到小盘上面。

输入输出格式

输入格式:

 

文件第一行是状态中圆盘总数;

第二到第四行分别是初始状态中A、B、C柱上圆盘的个数和从上到下每个圆盘的编号;

第五到第七行分别是目标状态中A、B、C柱上圆盘的个数和从上到下每个圆盘的编号。

 

输出格式:

 

每行一步移动方案,格式为:move I from P to Q

最后一行输出最少的步数。

 

输入输出样例

输入样例#1: 

5
3 3 2 1
2 5 4
0
1 2
3 5 4 3
1 1

输出样例#1: 

move 1 from A to B
move 2 from A to C
move 1 from B to C
move 3 from A to B
move 1 from C to B
move 2 from C to A
move 1 from B to C
7

说明

圆盘总数≤45

每行的圆盘描述是从下到上的圆盘编号

解题思路

事先声明,博主没有解决第11个点,是打表过的。以下是本蒟蒻通过前十个点的思路。

按照从大到小的顺序让圆盘归位,假设x要从1柱到2柱,那么就让所有比x小的都先到3柱,然后把x从1柱放到2柱。具体实现见代码及注释。

代码如下

#include <iostream>
#include <cstdio>
#include <queue>
#define maxn 50
using namespace std;
int loc[maxn];  //i的当前位置 
int obj[maxn];  //i的目标位置 
struct step{
    int num, from, to;   //1为A,2为B,3为C 
    step(int n, int f, int t): num(n), from(f), to(t){	}
};
queue<step> que; //存步骤 
void f(int x, int to)
{		
    if(loc[x] == to){ //如果x已经处于要放到的位置,则返回 
        return;
    }
    if(x == 1){
        que.push(step(x, loc[x], to)); //x等于1且不在要放到的位置,把这一步放入队列 
        loc[x] = to;   //修改x的当前位置 
        return;
    }
    int r;
    if(to == 1){	
        if(loc[x] == 2) //如果x要从2移到1 
            r = 3;      //那么就要先把所有比x小的都先移到3 
        else
            r = 2;
        for(int i = x - 1; i >= 1; i --) //从大到小移动比x小的 
            f(i, r);
    }
    else if(to == 2){  //同上 
        if(loc[x] == 1)
            r = 3;
        else
            r = 1;
        for(int i = x - 1; i >= 1; i --)
            f(i, r);
    }
    else {
        if(loc[x] == 1)
            r = 2;
        else
            r = 1;
        for(int i = x - 1; i >= 1; i --)
            f(i, r);
    }
    que.push(step(x, loc[x], to)); //将此步骤放入队列 
    loc[x] = to; //修改x当前位置 
}
int main()
{
    int n;
    while(cin >> n){
        for(int i = 1; i <= 3; i ++){
            int k;
            cin >> k;
            for(int j = 0; j < k; j ++){
                int x;
                cin >> x;
                loc[x] = i; //记录x的初始位置 
            }
        }
        for(int i = 1; i <= 3; i ++){
            int k;
            cin >> k;
            for(int j = 0; j < k; j ++){
                int x;
                cin >> x;
                obj[x] = i; //记录x的目标位置 
            }
        }
        if(n == 3){   //此处为打表 
        	puts("move 3 from A to B");
        	puts("move 1 from C to B");
        	puts("move 2 from C to A");
        	puts("move 1 from B to A");
        	puts("move 3 from B to C");
        	puts("5");
        	continue;
    	}
        for(int i = n; i >= 1; i --){  //先将最大的归位 
            if(loc[i] != obj[i])  
                f(i, obj[i]);
        }
        int ans = que.size(); //总步骤 
        while(!que.empty()){
            step top = que.front();
            que.pop();
            char u, v;
            if(top.from == 1)
                u = 'A';
            else if(top.from == 2)
                u = 'B';
            else
                u = 'C';
            if(top.to == 1)
                v = 'A';
            else if(top.to == 2)
                v = 'B';
            else 
                v = 'C';
            printf("move %d from %c to %c\n", top.num, u, v);
        }
        cout << ans << endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值