【題目背景】 在成功地發明瞭魔方之後,魯比克先生髮明瞭它的二維版本,稱作魔板。這是一張有8個大小相同的格子的魔板: 【題目描述】 我們知道魔板的每一個方格都有一種顏色。這8種顏色用前8個正整數來表示。可以用顏色的序列來表示一種魔板狀態,規定從魔板的左上角開始,沿順時針方向依次取出整數,構成一個顏色序 ...
【題目背景】
在成功地發明瞭魔方之後,魯比克先生髮明瞭它的二維版本,稱作魔板。這是一張有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個字元。
【輸入輸出樣例】
輸入:
2 6 8 4 5 7 3 1
輸出:
7
BCABCCB
【分析】
眾所周知,這是一道廣搜題,那麼本題的大體思路就明確了,剩下的就是耐心地解決一些細節問題。
降維打擊
魔板原本是2X4的矩陣,但一維處理起來一定比二維方便,於是便可以降維,但,要註意技巧。
以樣例來說,括弧裡面代表這個數儲存的一維數組的位置
2(a1) | 6(a2) | 8(a3) | 4(a4) |
5(a5) | 7(a6) | 3(a7) | 1(a8) |
具體實現請看代碼:
for(int i=1;i<=8;i++){//基本狀態
if(i<=4) sak[1].before[i]=i;
if(i>4) sak[1].before[i]=13-i;
}
for(int i=1;i<=4;i++)//雙迴圈輸入目標狀態(真~~朴素~~)
scanf("%d",&after[i]);
for(int i=8;i>=5;i--)
scanf("%d",&after[i]);
判重問題
8個數排列組合一定,所以只需要判定前七個數就一定能知道最後一個數,這樣就不會超出記憶體限制啦。然後用標記數組給這個七位數打個標記。
int pan(int a[]){//自定義pan函數用來判重
int ans=0;
for(int i=7;i>=1;i--)
ans=ans*10+a[i];
return ans;
}
三種操作
無腦模擬。合理使用結構體使代碼不複雜
儘量保證廣搜框架完整
其他細節問題
AC代碼
#include <bits/stdc++.h>
using namespace std;
int after[9],ans,o,jishu;//after數組為目標狀態,o和jishu為累加器輔助判斷一些奇怪的東西
bool fla[9000005],k;
struct sakura{//結構體
int before[9],f;char step;
}sak[100086];
int pan(int a[]){//自定義pan函數用來判重
int ans=0;
for(int i=7;i>=1;i--)
ans=ans*10+a[i];
return ans;
}
bool judge(int a[]){
for(int i=1;i<=8;i++)
if(a[i]!=after[i])
return 0;
return 1;
}
void print(int a){//遞歸輸出
if(sak[a].f!=0){
o++;
print(sak[a].f);
}
if(!sak[a].f) return;
if(!k){//輸出步數
printf("%d\n",o);
k=1;
}
printf("%c",sak[a].step);
jishu++;
if(!jishu%60)//隔60個換行
printf("\n");
}
void bfs(){
int h=0,t=1;sak[t].f=0;
while(h<t){
h++;
for(int i=1;i<=3;i++){//保證框架完整
int bit[9];
if(i==1){//A操作
for(int i=1;i<=4;i++){
bit[i]=sak[h].before[i+4];
bit[i+4]=sak[h].before[i];
}
}
if(i==2){//B操作
bit[1]=sak[h].before[4];bit[5]=sak[h].before[8];
bit[2]=sak[h].before[1];bit[6]=sak[h].before[5];
bit[3]=sak[h].before[2];bit[7]=sak[h].before[6];
bit[4]=sak[h].before[3];bit[8]=sak[h].before[7];
}
if(i==3){//C操作
bit[1]=sak[h].before[1];
bit[2]=sak[h].before[6];
bit[3]=sak[h].before[2];
bit[4]=sak[h].before[4];
bit[5]=sak[h].before[5];
bit[8]=sak[h].before[8];
bit[7]=sak[h].before[3];
bit[6]=sak[h].before[7];
}
if(!fla[pan(bit)]){
t++;
if(i==1) sak[t].step='A';
if(i==2) sak[t].step='B';
if(i==3) sak[t].step='C';
fla[pan(bit)]=1;//標記
sak[t].f=h;//記錄爸爸
for(int i=1;i<=8;i++)
sak[t].before[i]=bit[i];
if(ans==pan(bit)){
print(t);
exit(0);//萬惡之源結束
}
}
}
}
}
int main(){
for(int i=1;i<=8;i++){//降維打擊
if(i<=4) sak[1].before[i]=i;
if(i>4) sak[1].before[i]=13-i;
}
fla[pan(sak[1].before)]=1;
for(int i=1;i<=4;i++)
scanf("%d",&after[i]);
for(int i=8;i>=5;i--)
scanf("%d",&after[i]);
ans=pan(after);
if(ans==pan(sak[1].before)){//特判(貌似並不需要)
printf("0\n");
return 0;
}
bfs();//萬惡之源開始
return 0;
}