题意:类似于魔方的那种智力玩具(不过这个是二维的),通过旋转与最后状态匹配即可。编号顺序:左轮顺时针,右轮逆时针。
思路:1.BFS,每转一次记录一个状态,利用HASH判重。
2.超过16步就退出。
目标状态:
0 3 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1
旋转一次的状态(方便写出旋转函数):
LWC: 2 1 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 5 0 1
RWC: 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 1 2 1 0 7
LWCC: 4 3 0 5 6 5 0 1 2 1 0 3 0 7 8 7 0 9 10 9 0 1 0 3
RWCC: 0 3 4 3 0 5 6 5 0 9 0 1 2 1 0 7 8 7 0 9 10 9 0 1
实现了以上思路后发现程序的状态还是多得装不下,第二组SAMPLE就过不了,把自己的小Y卡得不行,后来去论坛上看了说存8步,我还是没看懂什么意思,又百度了一下,看到了双向BFS,于是终于得到了算法。从最终状态开始走9步,初始状态再走7步,若有重合状态,则在16步及其内可到达。
#include<stdio.h>
#include<string.h>
#define MAXSIZE 1000003
#define FORWARD 1
#define BACKWARD 2
int head[MAXSIZE],next[MAXSIZE];
int backhead[MAXSIZE],backnext[MAXSIZE];
const int final[24]={0,3,4,3,0,5,6,5,0,1,2,1,0,7,8,7,0,9,10,9,0,1,2,1};//final state
int origin[24],cur[24];//origin state and current state
int front,rear,flag,back;
typedef struct s
{
int state[24];
int step;
int action,fa;
}ST;
ST Save[MAXSIZE],BackSave[MAXSIZE];
void Initial()
{
int i;
memset(Save[0].state,0,sizeof(Save[0].state));
memset(BackSave[0].state,0,sizeof(BackSave[0].state));
BackSave[0].step=0;
Save[0].step=0;
Save[0].fa=BackSave[0].fa=-1;
BackSave[0].action=Save[0].action=0;
}
int hash(int state[])
{
int i,j,v=0,tmp[6];
memset(tmp,0,sizeof(tmp));
for(i=0;i<6;i++)
{
for(j=0;j<4;j++)tmp[i]+=state[i*4+j];
v=v*10+tmp[i];
v%=21474331;
}
return v%MAXSIZE;
}
int isExist(int n)
{
int h,u,bh,bu;
h=hash(Save[n].state);
u=head[h];
bh=h;
bu=backhead[bh];//Check whether current state can be found in BackSave array
if(!memcmp(BackSave[bh].state,Save[n].state,sizeof(Save[n].state)))
{
flag=n;
back=bh;
return 1;
}
while(bu)
{
if(!memcmp(BackSave[bu].state,Save[n].state,sizeof(Save[n].state)))
{
flag=n;
back=bu;
return 1;
}
bu=backnext[bu];
}
while(u)
{
if(!memcmp(Save[u].state,Save[n].state,sizeof(Save[n].state)))
{
return 1;
}
u=next[u];
}
next[n]=head[h];
head[h]=n;
return 0;
}
int isBackExist(int n)
{
int h,u;
h=hash(BackSave[n].state);
u=backhead[h];
while(u)
{
if(!memcmp(BackSave[u].state,BackSave[n].state,sizeof(BackSave[n].state)))
{
return 1;
}
u=backnext[u];
}
backnext[n]=backhead[h];
backhead[h]=n;
return 0;
}
int Insert(int mode,int order)//Save a state
{
if(order==FORWARD)
{
Save[rear].action=mode;
Save[rear].fa=front;
if(!isExist(rear))
{
Save[rear].step=Save[front].step+1;
if(Save[rear].step>7)return 0;
rear++;
}
}
else
{
if(!isBackExist(rear))
{
BackSave[rear].action=mode;
BackSave[rear].fa=front;
BackSave[rear].step=BackSave[front].step+1;
if(BackSave[rear].step>9)return 0;
rear++;
}
}
return 1;
}
void OutPut(int n)
{
if(n==-1||!Save[n].action)return;
OutPut(Save[n].fa);
printf("%d",Save[n].action);
}
void OrderOutPut(int n)
{
if(n==-1||!BackSave[n].action)return;
printf("%d",BackSave[n].action);
OrderOutPut(BackSave[n].fa);
}
int LWC(int n,int state[],int order)//Left Wheel Clockwise rotation
{//2 1 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 5 0 1
if(flag>=0)return 1;
int i,j,k;
for(i=0;i<12;i++)
{
state[i]=cur[(i+10)%12];
}
for(i=12;i<24;i++)
{
state[i]=cur[i];
if(i>20)state[i]=state[i%12];
}
if(!Insert(n,order))return 0;
return 1;
}
int RWC(int n,int state[],int order)//Right Wheel Clockwise rotation
{// 0 3 4 3 0 5 6 5 0 1 0 7 8 7 0 9 10 9 0 1 2 1 0 7
if(flag>=0)return 1;
int i,j,k;
for(i=0;i<9;i++)
{
state[i]=cur[i];
}
for(i=9;i<24;i++)
{
state[i]=cur[(i+2)%24];
if(i>20)state[i]=state[i-12];
}
if(!Insert(n,order))return 0;
return 1;
}
int LWCC(int n,int state[],int order)//Left Wheel Counter-Clockwise rotation
{// 4 3 0 5 6 5 0 1 2 1 0 3 0 7 8 7 0 9 10 9 0 1 0 3
if(flag>=0)return 1;
int i,j,k;
for(i=0;i<12;i++)
{
state[i]=cur[(i+14)%12];
}
for(i=12;i<24;i++)
{
state[i]=cur[i];
if(i>20)state[i]=state[i%12];
}
if(!Insert(n,order))return 0;
return 1;
}
int RWCC(int n,int state[],int order)//Right Wheel Counter-Clockwise rotation
{//0 3 4 3 0 5 6 5 0 9 0 1 2 1 0 7 8 7 0 9 10 9 0 1
if(flag>=0)return 1;
int i,j,k;
for(i=0;i<9;i++)
{
state[i]=cur[i];
}
for(i=9;i<24;i++)
{
if(i<=13)state[i]=cur[i+10];
if(i>13&&i<=20)state[i]=cur[i-2];
if(i>20)state[i]=state[i-12];
}
if(!Insert(n,order))return 0;
return 1;
}
void BackBFS()
{//save final state to middle state(about 9 steps)
front=rear=0;
memcpy(BackSave[rear++].state,final,sizeof(final));
while(front<rear)
{
memcpy(cur,BackSave[front].state,sizeof(cur));
if(!LWC(3,BackSave[rear].state,BACKWARD))break;
if(!RWC(4,BackSave[rear].state,BACKWARD))break;
if(!LWCC(1,BackSave[rear].state,BACKWARD))break;
if(!RWCC(2,BackSave[rear].state,BACKWARD))break;
front++;
}
}
void BFS()
{
memset(head,0,sizeof(head));
memset(next,0,sizeof(next));
front=rear=0;
memcpy(Save[rear++].state,origin,sizeof(origin));
isExist(front);
if(flag>=0)
{
OutPut(flag);
OrderOutPut(back);
printf("\n");
return;
}
while(front<rear)
{
if(!memcmp(Save[front].state,final,sizeof(final)))
{
OutPut(front);
printf("\n");
return;
}
memcpy(cur,Save[front].state,sizeof(cur));
if(!LWC(1,Save[rear].state,FORWARD))break;
if(!RWC(2,Save[rear].state,FORWARD))break;
if(!LWCC(3,Save[rear].state,FORWARD))break;
if(!RWCC(4,Save[rear].state,FORWARD))break;
if(flag>=0)
{
OutPut(flag);
OrderOutPut(back);
printf("\n");
return;
}
front++;
}
printf("NO SOLUTION WAS FOUND IN 16 STEPS\n");
}
int main()
{
int puzzle;
scanf("%d",&puzzle);
int i,j,k;
memset(backhead,0,sizeof(backhead));
memset(backnext,0,sizeof(backnext));
back=flag=-1;
BackBFS();
for(i=0;i<puzzle;i++)
{
Initial();
back=flag=-1;
for(j=0;j<24;j++)scanf("%d",&origin[j]);
if(memcmp(origin,final,sizeof(final))==0)
{
printf("PUZZLE ALREADY SOLVED\n");
}
else
{
BFS();
}
}
return 0;
}