sicily 1150 简单魔板 sicily 1151 魔板 sicily 1515 魔板C

这三道题目大致相同,只是数据处理方式不一样,须要修改的地方不多,所以只以1150为例说明便可。 node

Description

魔板由8个大小相同方块组成,分别用涂上不一样颜色,用18的数字表示。 ios

其初始状态是 数组

1 2 3 4 函数

8 7 6 5 spa

对魔板可进行三种基本操做: code

A操做(上下行互换): orm

8 7 6 5 ip

1 2 3 4 ci

B操做(每次以行循环右移一个): string

4 1 2 3

5 8 7 6

C操做(中间四小块顺时针转一格):

1 7 2 4

8 6 3 5

用上述三种基本操做,可将任一种状态装换成另外一种状态。

Input

输入包括多个要求解的魔板,每一个魔板用三行描述。

第一行步数N不超过10的整数),表示最多允许的步数。

第2、第三行表示目标状态,按照魔板的形状,颜色用18的表示。

N 等于 -1 的时候,表示输入结束。

Output

对于每个要求解的魔板,输出一行。

首先是一个整数M,表示你找到解答所须要的步数。接着若干个空格以后,从第一步开始按顺序给出M步操做(每一步是ABC),相邻两个操做之间没有任何空格。

注意:若是不能达到,则 M 输出 -1 便可。

Sample Input

4
5 8 7 6
4 1 2 3
3
8 7 6 5
1 2 3 4
-1

Sample Output

2 AB
1 A

评分:M超过N或者给出的操做不正确均不能得分。

分析:

本题由于题目的特殊性有两种解法,一种是比较普通的广搜法(BFS),另一种是利用魔板性质构造哈希表的方法。二者相较,方法一更直观,普适性强些,方法二更巧妙,固然速度更快些。同时,本题又要注意数据处理,由于到1151和1515的时候,数据量变大,对数据存储和计算要求变高,因此并不推荐用数组存储魔板状态。观察下发现,魔板只有八个格子,彻底能够将八个数字变成一串;而想到整数计算和存储性质仍不够理想,能够用3位二进制数表示单个的数字位,那样变化函数就变成了位运算,速度大幅增长,同时存储要求也下降了不少。(固然,用数组作也能够用一些数据压缩的办法,可是会让数据存储和运算部分变得复杂,并不推荐。)

解法一:

由于有三种变化方法,因此很直观的想到直接搜索。视本题要求为找出图中特定起点和重点间的通路,且通路长度有限制,天然会想到BFS方法。直接套用BFS方法,便可得出答案。

解法二:

本题题目很特殊,魔板的三种变化其实每一种都是能够循环必定次数再回到初始状态的,并且明显状态A到状态B的操做反过来就能够获得状态B到状态A的操做流程。同时,咱们发现,解法一每次操做都要从相同的起点开始查找相同的路径,这样太浪费时间,能够制做一个哈希表存储广搜法的遍历结果。而后,将原先的初始状态做为目标状态,根据循环操做的性质不断回溯,找到如何构造它的方法,将这一操做序列反向输出就是答案。

代码:

解法一:直接广度优先搜索

// Problem#: 1150
// Submission#: 1786358
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <queue>
#include <string>
#include <cstring>
using namespace std;

int  a[8] = { 1 , 2 , 3 , 4 , 8 , 7 , 6 , 5 } ;
bool visit[1<<24];

struct node{
    int code;
    string path;
    node(){
    code = 0;
    path = "";
    }
}begin,end;

inline  int  A( int  n) { return  (n & 4095 ) << 12 | n >> 12 ;}

inline  int  B( int  n) { return  (( 7 << 9 | 7 << 21 ) & n) >> 9   |  ( ~ ( 7 << 9 | 7 << 21 ) & n) << 3 ;}

inline  int  C( int  n) { return  ( 7 | 7 << 9 | 7 << 12 | 7 << 21 ) & n  |  (( 7 << 3 ) & n) << 3   |  (( 7 << 6 ) & n) << 12   |  (( 7 << 18 ) & n) >> 3   |  (( 7 << 15 ) & n) >> 12 ;}

inline  int  zip( int  a[]) {
    int  s = 0 ;
    for ( int  i = 0 ;i < 8 ; ++ i) s |= (a[i] - 1 ) << ( 3 * i);
    return  s;
}

void bfs(int n){
    queue<node> buffer;
    buffer.push(begin);
    visit[begin.code] = true;
    node t;
    int v;
    while(!buffer.empty()){
    t = buffer.front();
    buffer.pop();
    if(t.path.size()>n){
        cout << "-1" << endl;
        return ;
    }
    if(t.code==end.code){
        cout << t.path.size() << " " << t.path << endl;
        return ;
    }
    node in;
    v = A(t.code);
    if(!visit[v]){
        visit[v] = true;
        in.code = v;
        in.path = t.path + "A";
        buffer.push(in);
    }
    v = B(t.code);
    if(!visit[v]){
        visit[v] = true;
        in.code = v;
        in.path = t.path + "B";
        buffer.push(in);
    }
    v = C(t.code);
    if(!visit[v]){
        visit[v] = true;
        in.code = v;
        in.path = t.path + "C";
        buffer.push(in);
    }
    }
}

int main(){
    int n;
    int temp[8],re;
    begin.code = zip(a);

    while(cin>>n && n!=-1){
    for( int i=0 ; i<8 ; i++ ) cin >> temp[i];
    end.code = zip(temp);
    memset(visit,0,sizeof(visit));
    bfs(n);
    }
    return 0;
}
解法二:哈希表
// Problem#: 1150
// Submission#: 1781837
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio> 
char  hash[ 1 << 24 ]; 
inline  int  A( int  n) { return  (n & 4095 ) << 12 | n >> 12 ;} // 4095=2^12-1
inline  int  B( int  n) { return  (( 7 << 9 | 7 << 21 ) & n) >> 9   |  ( ~ ( 7 << 9 | 7 << 21 ) & n) << 3 ;}
inline  int  C( int  n) { return  ( 7 | 7 << 9 | 7 << 12 | 7 << 21 ) & n  |  (( 7 << 3 ) & n) << 3   |  (( 7 << 6 ) & n) << 12   |  (( 7 << 18 ) & n) >> 3   |  (( 7 << 15 ) & n) >> 12 ;}
inline  int  zip( int  a[]) { 
    int  s = 0 ;
    for ( int  i = 0 ;i < 8 ; ++ i) s |= (a[i] - 1 ) << ( 3 * i);
    return  s;
}
int  a[] = { 1 , 2 , 3 , 4 , 8 , 7 , 6 , 5 } ; 
const   int  QLen = 10000 ; 
int  q[QLen],b = 0 ,e = 0 ; 
inline  void  inc( int &  p){ if(++ p ==QLen) p=0;} 
int main(){
   int i,j,n,bgn=zip(a);
    hash[bgn]='E';
      q[b]=bgn; inc(b);
      while(b!=e){
         i=q[e]; inc(e);
         j=A(i);
         if(!hash[j]) hash[j]='A', q[b]=j, inc(b);
         j=B(i);
         if(!hash[j]) hash[j]='B', q[b]=j, inc(b);
         j=C(i);
         if(!hash[j]) hash[j]='C', q[b]=j, inc(b);
      }
      char s[100];
      while(scanf("%d",&n),n!=-1){
         for(i=0; i<8; ++i) scanf("%d",&a[i]);
         for(i=zip(a),j=0; i!=bgn; ++j){
            s[j]=hash[i];
            switch(s[j]){
               case 'A': i=A(i);        break;
               case 'B': i=B(B(B(i)));    break;
               case 'C': i=C(C(C(i)));    break;
            }
         }
         if(j>n) printf("-1\n");
         else{
            printf("%d ",j);
            while(j--) putchar(s[j]);
            putchar('\n');
         }
      }
      return 0;
}
相关文章
相关标签/搜索