這三道題目大致相同,只是數據處理方式不一樣,須要修改的地方不多,所以只以1150爲例說明便可。 node
魔板由8個大小相同方塊組成,分別用塗上不一樣顏色,用1到8的數字表示。 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
用上述三種基本操做,可將任一種狀態裝換成另外一種狀態。輸入包括多個要求解的魔板,每一個魔板用三行描述。
第一行步數N(不超過10的整數),表示最多允許的步數。
第2、第三行表示目標狀態,按照魔板的形狀,顏色用1到8的表示。
當 N 等於 -1 的時候,表示輸入結束。對於每個要求解的魔板,輸出一行。
首先是一個整數M,表示你找到解答所須要的步數。接着若干個空格以後,從第一步開始按順序給出M步操做(每一步是A、B或C),相鄰兩個操做之間沒有任何空格。
注意:若是不能達到,則 M 輸出 -1 便可。4 5 8 7 6 4 1 2 3 3 8 7 6 5 1 2 3 4 -1
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; }