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

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

Solution:

  最近太蠢了,打了个爆搜,爆$0$`~`。。。

  正解思路实在是巧妙,我们处理出每个盘的起始位置和目标位置,然后贪心的想到,我们应该从大到小让盘依次移到目标位置,移动过程中就是让小盘让路(即移到另一个中间盘上),然后每次就层层递归,输出就好了。(怎么会有这么巧的思路~)

代码:

#include<bits/stdc++.h>
#define il inline
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=55;
int n,fr[N],to[N],ans;
string s="ABC";

il void dfs(int u,int v){
    if(fr[u]==v)return;
    Bor(i,1,u-1) dfs(i,6-fr[u]-v);
    printf("move %d from %c to %c
",u,s[fr[u]-1],s[v-1]);
    fr[u]=v,ans++;
}

int main(){
    cin>>n;
    int t,x;
    For(i,1,3){
        cin>>t;
        while(t--)cin>>x,fr[x]=i;
    }
    For(i,1,3){
        cin>>t;
        while(t--)cin>>x,to[x]=i;
    }
    Bor(i,1,n) dfs(i,to[i]);
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/five20/p/9138583.html