题目描述
在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有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个字符。
Sample Input
2 6 8 4 5 7 3 1
Sample Output
7
BCABCCB
分析:简单的BFS。因为题目最后要输出序列,所以BFS时要用一个数组模拟队列,这样能在打到最终状态时,向前查找到之前的每一步。每次找到一步,将这次的操作压入栈中,最后一个个弹出,就能得到操作序列。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <stack>
#include <ctime>
#include <cmath>
#include <map>
#include <set>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define db1(x) cout<<#x<<"="<<(x)<<endl
#define db2(x,y) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<endl
#define db3(x,y,z) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<endl
#define db4(x,y,z,a) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<", "<<#a<<"="<<(a)<<endl
#define db5(x,y,z,a,r) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<", "<<#a<<"="<<(a)<<", "<<#r<<"="<<(r)<<endl
using namespace std;
typedef struct node
{
int cnt,fat,index;
char kind;
}node;
int get_num(int temp[][4])
{
int cnt=0;
for(int i=0;i<4;++i)
cnt=cnt*10+temp[0][i];
for(int i=3;i>=0;--i)
cnt=cnt*10+temp[1][i];
return cnt;
}
int fun_A(int num[][4])
{
int temp[2][4];
for(int i=0;i<4;++i)
temp[0][i]=num[1][i],temp[1][i]=num[0][i];
return get_num(temp);
}
int fun_B(int num[][4])
{
int temp[2][4];
for(int i=1;i<4;++i)
temp[0][i]=num[0][i-1],temp[1][i]=num[1][i-1];
temp[0][0]=num[0][3],temp[1][0]=num[1][3];
return get_num(temp);
}
int fun_C(int num[][4])
{
int temp[2][4];
for(int i=0;i<4;++i)
temp[0][i]=num[0][i],temp[1][i]=num[1][i];
int a=num[0][1],b=num[0][2],d=num[1][1],c=num[1][2];
temp[0][1]=d,temp[0][2]=a,temp[1][2]=b,temp[1][1]=c;
return get_num(temp);
}
void print(node num,vector<node>que,int index)
{
printf("%d\n",num.index);
stack<node>sta;sta.push(num);
while(1)
{
node temp=sta.top();
if(temp.fat==-1)break;
temp=que[temp.fat];
sta.push(temp);
}
int t=0,times=0;
while(!sta.empty())
{
node temp=sta.top();sta.pop();
if(temp.fat==-1)continue;
printf("%c",temp.kind);times++;
if(times==60)times=0,printf("\n");
}
return;
}
int main(void)
{
#ifdef test
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
clock_t start=clock();
#endif //test
int fin=0;//fin代表最后的状态,数字是按照顺时针得到的
for(int i=0;i<8;++i)
{
int a;scanf("%d",&a);
fin=fin*10+a;
}
node fir;fir.cnt=12345678,fir.fat=-1,fir.index=0;
unordered_map<int,int>ump;ump[12345678]=1;//初始状态已经出现过了
vector<node>que;que.push_back(fir);//vector模拟队列
int l=0,r=1,f=0;
while(l<r)
{
int ll=l,rr=r;l=rr;
for(ll;ll<rr;++ll)
{
node now=que[ll];
if(now.cnt==fin)
{
f=1;
print(now,que,ll);
break;
}
int temp_now[2][4],temp_cnt=now.cnt;
for(int i=0;i<4;++i)temp_now[1][i]=temp_cnt%10,temp_cnt/=10;
for(int i=3;i>=0;--i)temp_now[0][i]=temp_cnt%10,temp_cnt/=10;
node next_A,next_B,next_C;
next_A.cnt=fun_A(temp_now),next_B.cnt=fun_B(temp_now),next_C.cnt=fun_C(temp_now);
next_A.fat=next_B.fat=next_C.fat=ll;
next_A.index=next_B.index=next_C.index=now.index+1;
next_A.kind='A',next_B.kind='B',next_C.kind='C';
if(ump[next_A.cnt]!=1)ump[next_A.cnt]=1,que.push_back(next_A),r++;
if(ump[next_B.cnt]!=1)ump[next_B.cnt]=1,que.push_back(next_B),r++;
if(ump[next_C.cnt]!=1)ump[next_C.cnt]=1,que.push_back(next_C),r++;
}
if(f)break;
}
#ifdef test
clockid_t end=clock();
double endtime=(double)(end-start)/CLOCKS_PER_SEC;
printf("\n\n\n\n\n");
cout<<"Total time:"<<endtime<<"s"<<endl; //s为单位
cout<<"Total time:"<<endtime*1000<<"ms"<<endl; //ms为单位
#endif //test
return 0;
}