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

题面

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
");
	    	     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;
}
原文地址:https://www.cnblogs.com/cjyyb/p/7197284.html