【CJOJ1372】【洛谷2730】【USACO 3.2.5】魔板

时间:2024-01-02 18:45:50

题面

Description

在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有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

对于每种可能的状态,这三种基本操作都可以使用。

你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。

Input

只有一行,包括8个整数,用空格分开(这些整数在范围 1——8 之间)不换行,表示目标状态。

Output

Line 1: 包括一个整数,表示最短操作序列的长度。

Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。

Sample Input

2 6 8 4 5 7 3 1

Sample Output

7

BCABCCB

题解

看到题目,很容易就可以想到使用BFS

而状态最多只有8!中,不到50000

完全可以使用数组直接存储

但是我用的是状压(有点麻烦自己。。。。)

然后使用map判重(用康托展开也可以的)

用了STL效率偏低

但是能够AC

其中一定要注意顺序和编号的问题(细节!)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
struct Node
{
int st;//步数
int t;//状态
int ff;//父节点
char way;//方式
}Q[50000];
int h,t;
int End,Beg=12348765;
//bool vis[50000];
map<int,bool> vis;
inline int read()
{
register int x=0,t=1;register char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x;
}
int ten[8]={1,10,100,1000,10000,100000,1000000,10000000};
int change(int tt,int x,int y)//交换状态tt的x位和y位
{
int ttt=tt,a,b;
for(int i=1;i<x;++i)
ttt/=10;
a=ttt%10;
for(int i=x;i<y;++i)
ttt/=10;
b=ttt%10;
return tt-(a-b)*ten[x-1]+(a-b)*ten[y-1];
}
void outp(int t)
{
vector<Node> Ans;
while(t!=1)
{
Ans.push_back(Q[t]);
t=Q[t].ff;
}
int si=Ans.size();
cout<<si<<endl;
for(int i=0;i<si;++i)
{
cout<<Ans[si-i-1].way;
if(i%60==59)cout<<endl;
}
}
int main()
{
for(int i=8;i>=5;--i)
End+=(read()*ten[i-1]);
for(int i=1;i<=4;++i)
End+=(read()*ten[i-1]);
Q[1]=(Node){0,Beg,0,0};
if(Beg==End)//初始时相同
{
printf("0\n");
return 0;
}
vis[Beg]=true;
h=0,t=1;
while(h<t)
{
Node now=Q[++h];
int s;
//变化A
s=now.t;
for(int i=1;i<=4;++i)
s=change(s,i,i+4);//上下交换
if(vis.find(s)==vis.end())//没有访问过
{
vis[s]=true;
Q[++t]=(Node){now.st+1,s,h,'A'};
}
if(s==End)
{
outp(t);
return 0;
}
//变化B
s=now.t;
for(int i=1;i<=3;++i)
s=change(s,i,i+1);
for(int i=5;i<=7;++i)
s=change(s,i,i+1);
if(vis.find(s)==vis.end())
{
vis[s]=true;
Q[++t]=(Node){now.st+1,s,h,'B'};
}
if(s==End)
{
outp(t);
return 0;
}
//变化C
s=now.t;
s=change(s,2,3);
s=change(s,2,7);
s=change(s,2,6);
if(vis.find(s)==vis.end())
{
vis[s]=true;
Q[++t]=(Node){now.st+1,s,h,'C'};
}
if(s==End)
{
outp(t);
return 0;
}
}
return 0;
}