魔板
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4050 Accepted Submission(s): 951
1 2 3 4
8 7 6 5
對於魔板,可施加三種不同的操作,具體操作方法如下:
A: 上下兩行互換,如上圖可變換爲狀態87654321
B: 每行同時循環右移一格,如上圖可變換爲41236785
C: 中間4個方塊順時針旋轉一格,如上圖可變換爲17245368
給你魔板的初始狀態與目標狀態,請給出由初態到目態變換數最少的變換步驟,若有多種變換方案則取字典序最小的那種。
思路:是先了解了康託展開再做這道題,想當於是用康拓展開給每一種狀態弄一個獨立的標號,可以快速找到某一種狀態,所以就是先用12345678爲初始狀態,然後記錄每一種狀態的contor值,這裏我用了把函數寫在結構體裏的方法,方便簡潔(學習了網上一位大佬),然後比較難想就是,每一次輸入的初態和末態並不都是12345678,如何將輸入和bfs中的狀態對應起來呢?
我們就需要置換一下。
置換: 原始態爲“12345678” 例如 初態是 “45781236” 目態是 ”78451326“
目態的第一位‘7’ 在初態中是第三位, 而原始態的第三位是‘3’,故目態的第一位應該轉換爲‘3’,(就是將輸入的值和12345678一一對應)就這樣一次轉換 最後目態轉換爲 34125768, 最後找出34125768對應的康拓值,輸出就好了。
而字典序的話,每一次bfs都是按照ABC這樣的順序的,所以每種狀態的步驟必然是最小字典序。
具體看代碼。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<bitset>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
using namespace std;
typedef long long ll;
const int N=40320+10;
int fact[9]= {1,1,2,6,24,120,720,5040,40320};
struct info{
int arr[8];
int val;//計算出來的康託展開的序號
string step;
void contor(){//把康託展開寫在結構體裏面
val=0;
for(int i=0;i<8;i++){
int t=0;
for(int j=i+1;j<8;j++){
if(arr[j]<arr[i])t++;
}
val+=t*fact[8-i-1];
}
val++;
}
void change_a(){
reverse(arr,arr+8);
step+='A';
}
void change_b(){
int temp=arr[3];
for (int i=3; i>0; --i)
arr[i]=arr[i-1];
arr[0]=temp;
temp=arr[4];
for (int i=4; i<7; ++i)
arr[i]=arr[i+1];
arr[7]=temp;
step+="B";
}
void change_c(){
int temp=arr[1];
arr[1]=arr[6];
arr[6]=arr[5];
arr[5]=arr[2];
arr[2]=temp;
step+='C';
}
};
int vis[N];
string ans[N];//記錄每一種狀態的操作
int re[8];
info s,t;
void bfs(){
queue<info>q;
vis[s.val]=1;
q.push(s);
info now,v;
while(!q.empty()){
now=q.front();
q.pop();
v=now;
int len=v.step.length();
if(len<1||v.step[len-1]!='A'){//去掉AA這樣的情況
v.change_a();
v.contor();
if(!vis[v.val]){
vis[v.val]=1;
ans[v.val]=v.step;
q.push(v);
}
}
v=now;
if(len<3||v.step[len-1]!='B'||v.step[len-2]!='B'||v.step[len-3]!='B'){//去掉BBBB這樣的情況
v.change_b();
v.contor();
if(!vis[v.val]){
vis[v.val]=1;
ans[v.val]=v.step;
q.push(v);
}
}
v=now;
if(len<3||v.step[len-1]!='C'||v.step[len-2]!='C'||v.step[len-3]!='C'){//去掉CCCC這樣的情況
v.change_c();
v.contor();
if(!vis[v.val]){
vis[v.val]=1;
ans[v.val]=v.step;
q.push(v);
}
}
}
}
int main(){
for(int i=0;i<8;i++){
s.arr[i]=i+1;
}//初始化 12345678
s.contor();
bfs();
char ss[10];
while(scanf("%s",ss)!=EOF){
for(int i=0;i<8;i++){
re[ss[i]-'0']=i+1;
}//將輸入的初始狀態的字符 和12345678(bfs中的初始狀態)一一對應
scanf("%s",ss);
for(int i=0;i<8;i++){
t.arr[i]=re[ss[i]-'0'];//找到當前的目標狀態在bfs中對應的值
}
t.contor();
printf("%s\n",ans[t.val].c_str());
}
}