1. 程式人生 > >SSLOJ USACO 3.2 Magic Squares

SSLOJ USACO 3.2 Magic Squares

題目

題目背景

在成功地發明了魔方之後,魯比克先生髮明瞭它的二維版本,稱作魔板。這是一張有8個大小相同的格子的魔板:

1 2 3 4

8 7 6 5

題目描述

我們知道魔板的每一個方格都有一種顏色。這8種顏色用前8個正整數來表示。可以用顏色的序列來表示一種魔板狀態,規定從魔板的左上角開始,沿順時針方向依次取出整數,構成一個顏色序列。對於上圖的魔板狀態,我們用序列(1,2,3,4,5,6,7,8)來表示。這是基本狀態。

這裡提供三種基本操作,分別用大寫字母“A”,“B”,“C”來表示(可以通過這些操作改變魔板的狀態):

“A”:交換上下兩行;

“B”:將最右邊的一列插入最左邊;

“C”:魔板中央四格作順時針旋轉。

下面是對基本狀態進行操作的示範:

A: 8 7 6 5

1 2 3 4

B: 4 1 2 3

5 8 7 6

C: 1 7 2 4

8 6 3 5

對於每種可能的狀態,這三種基本操作都可以使用。

你要程式設計計算用最少的基本操作完成基本狀態到目標狀態的轉換,輸出基本操作序列。

輸入輸出格式

輸入格式:

 

只有一行,包括8個整數,用空格分開(這些整數在範圍 1——8 之間)不換行,表示目標狀態。

 

輸出格式:

 

Line 1: 包括一個整數,表示最短操作序列的長度。

Line 2: 在字典序中最早出現的操作序列,用字串表示,除最後一行外,每行輸出60個字元。

 

分析

       雜湊+廣搜

       首先我們要開一個進行了‘A’‘B’‘C’轉換之後的陣列

       找序列的話,就在進入下一次轉換之前記住他的father

       深搜輸出即可

程式碼

 

   

 1 #include<cstdio>
 2 #include<string>
 3 using namespace std;
4 const int N=100003; 5 const int r[3][9]={{8,7,6,5,4,3,2,1},{4,1,2,3,6,7,8,5},{1,7,2,4,5,3,6,8}};//記住四次交換之後的位置 6 int father[N],num[N],xx,he,ta; 7 string s[N],ss,h[N]; 8 char lq[N]; 9 bool hash(string s) //雜湊 10 { 11 int ans=0; 12 for (int i=0;i<8;i++) 13 ans=(ans<<3)+(ans<<1)+s[i]-48; 14 int i=0; ans%=N; 15 while (i<N&&h[(i+ans)%N]!=""&&h[(i+ans)%N]!=s) 16 i++; 17 if (h[(i+ans)%N]=="") 18 { 19 h[(i+ans)%N]=s; 20 return false; 21 } else return true; 22 } 23 void bfs() //廣搜 24 { 25 hash("12345678"); 26 s[1]="12345678"; 27 he=0,ta=1; 28 do 29 { 30 he++; 31 for (int i=0;i<3;i++){ 32 ta++; 33 father[ta]=he; 34 s[ta]=""; 35 num[ta]=num[he]+1; 36 if (i==0) lq[ta]='A'; 37 if (i==1) lq[ta]='B'; 38 if (i==2) lq[ta]='C'; 39 for (int j=0;j<8;j++) 40 s[ta]+=s[he][r[i][j-1]]; 41 if (hash(s[ta])) ta--; 42 else if (s[ta]==ss) return; 43 } 44 }while(he<ta); 45 } 46 void write(int x) 47 { 48 if (x==1) return; 49 write(father[x]); 50 printf("%c",lq[x]); 51 } 52 53 int main() 54 { 55 for (int i=0;i<8;i++) 56 {scanf("%d",&xx);ss+=xx+48; } 57 if (ss=="12345678") printf("0"); else 58 { 59 bfs(); 60 printf("%d\n",num[ta]); 61 write(ta); 62 } 63 }