写此题的时候头脑必须十分清晰,不然旋转函数非常容易写错。。。建议先写测试后再写搜索函数。
16层,单向搜索的话时间空间开销都太大,可以采用正向8层,逆向8层的方式,如果相遇,则有解。
#include<cstdio>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
struct node
{
string s;
int fa;
int pa;
};
int dis[100000];
int dis2[100000];
int flag;
node q[100000];
node q2[100000];
int pos1;
int pos2;
map<string,int> m;
map<string,int> m2;
void tran(string &s,int k) //旋转函数
{
int i;
string ss=s;
if(k==1)
{
for(i=0; i<=9;i++) s[i+2]=ss[i];
s[0]=ss[10];s[1]=ss[11];
for(i=12;i<=20;i++) s[i]=ss[i];
}
else if(k==2)
{
for(i=9; i<=18;i++) s[i]=ss[i+2];
s[19]=ss[9]; s[20]=ss[10];
for(i=0;i<=8;i++) s[i] = ss[i];
}
else if(k==3)
{
for(i=0;i<=9;i++) s[i]=ss[i+2];
s[10]=ss[0];s[11]=ss[1];
for(i=12;i<=20;i++) s[i]=ss[i];
}
else if(k==4)
{
for(i=9;i<=18;i++) s[i+2]=ss[i];
s[9]= ss[19];s[10] = ss[20];
for(i=0;i<=8;i++) s[i]=ss[i];
}
s[21]=s[9];
s[22]=s[10];
s[23]=s[11];
}
void backbfs()
{
m2.clear();
int rear=1,front=1;
string ns="034305650121078709#90121";
q2[rear].fa=0;
q2[rear].s=ns;
m2[ns]=rear++;
while(front<rear)
{
for(int i=1;i<=4;i++)
{
ns=q2[front].s;
tran(ns,i);
if(m2.find(ns)==m2.end()) //扩展结点
{
dis2[rear]=dis2[front]+1;
q2[rear].s=ns;
q2[rear].fa=front;
if(i==1) q2[rear].pa=3;
else if(i==3) q2[rear].pa=1;
else if(i==2) q2[rear].pa=4;
else if(i==4) q2[rear].pa=2;
if(m.find(ns)!=m.end()) //遇上了正向搜索
{
pos1=m[ns];
pos2=rear;
flag=2;
return;
}
m2[ns]=rear++;
}
}
front++;
if(dis2[front]>=8)
{
return;
}
}
}
void bfs(string s) //正向搜索
{
m.clear();
int rear=1,front=1;
string ns;
q[rear].fa=0;
q[rear].s=s;
m[s]=rear++;
while(front<rear)
{
for(int i=1;i<=4;i++)
{
ns=q[front].s;
tran(ns,i);
if(m.find(ns)==m.end())
{
dis[rear]=dis[front]+1;
q[rear].s=ns;
q[rear].fa=front;
q[rear].pa=i;
if(ns=="034305650121078709#90121") //正向搜索已经找到答案
{
pos1=rear;
flag=1;
return;
}
m[ns]=rear++;
}
}
front++;
if(dis[front]>=8) //超过8层就逆向搜索
{
backbfs();
break;
}
}
}
void print(int i) //递归打印正向路径
{
if(i==1) return;
print(q[i].fa);
printf("%d",q[i].pa);
}
void print2(int i) //递推打印逆向的路径
{
while(i!=1)
{
printf("%d",q2[i].pa);
i=q2[i].fa;
}
}
int main()
{
int t;
scanf("%d",&t);
getchar();
while(t--)
{
memset(dis,0,sizeof(dis));
memset(dis2,0,sizeof(dis2));
int i=0,top=-1;
char a[60];
char b[40];
string s;
flag=0; //1代表正向找到,2代表正向+逆向找到,0代表没有找到
gets(a);
for(i=0;a[i];i++) //将char *转换成string类型,为了map判重用
{
if(a[i]==' ') continue;
if(a[i]=='1'&&a[i+1]=='0') {b[++top]='#';i++;continue;}
b[++top]=a[i];
}
b[++top]='\0';
s=b;
if(s=="034305650121078709#90121")
{
printf("PUZZLE ALREADY SOLVED\n");
continue;
}
bfs(s);
if(flag==2) {print(pos1);print2(pos2);putchar(10);}
else if(flag==1) {print(pos1);putchar(10);}
else printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
}
return 0;
}
//0 3 4 5 0 3 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1