和大多数ACMer一样,一开始,我习惯性的单项搜索,结果搞了一下午没搞出来,
看了人家的思路,我明白了单向搜16层是多么的可笑啊, 就算把数组开到最大也是不够用的。。。。
正确的做法应该是双向搜索
这样写了以后,我又呆了,还是不对,我忽略了逆向搜索输出路径是应该也是逆向的,就是说如果原来是逆向3搜过来的,输出是应该是输出3的逆向,就是1。
这是我做过搜索中少有的代码超长的题目,有点力不从心啊,
代码如下:
#include <cstdio>
#include <cstring>
#define MN 100003
using namespace std;
int ok, ans, ans2, head[MN], next[MN], fa[MN], pa[MN], step[MN];
int back_st[MN][24], st[MN][24], sta[24], _aim[24] = {0,3,4,3,0,5,6,5,0,1,2,1,0,7,8,7,0,9,10,9,0};
int back_head[MN], back_next[MN], back_fa[MN], back_pa[MN];
int is_ok()
{
for(int i = 0; i < 21; i++) if(sta[i]!=_aim[i]) return 0;
return 1;
}
int _strcmp(int *a, int *b)
{
for(int i = 0; i < 21; i++) if(a[i]!=b[i]) return 0;
return 1;
}
int hash(int cur)
{
int s = 0;
for(int i = 0; i < 2l; i++)
s = (s * 11 + st[cur][i])%MN;
return s;
}
int is_succeed(int cur)
{
int h = hash(cur);
int u = back_head[h];
while(u)
{
if(_strcmp(back_st[u],st[cur])) { ans2 = u; return 1;}
u = back_next[u];
}
return 0;
}
int try_to_insert(int cur)
{
int h = hash(cur);
int u = head[h];
while(u)
{
if(_strcmp(st[cur],st[u])) return 0;
u = next[u];
}
next[cur] = head[h];
head[h] = cur;
return 1;
}
void bfs(int *A, int state)
{
int rear = 0, front = 1;
step[0] = 0;
for(int i = 0; i < 21; i++) st[0][i] = A[i];
memset(head,0,sizeof(head));
memset(next,0,sizeof(next));
try_to_insert(0);
while(rear<front)
{
if(state>0&&is_succeed(rear)) { ok = 1; ans = rear; break; }
if(step[rear]>8) break;
for(int i = 0; i <= 9; i++) st[front][i+2] = st[rear][i];
st[front][0] = st[rear][10]; st[front][1] = st[rear][11];
for(int i = 12; i <= 20; i++) st[front][i] = st[rear][i];
if(try_to_insert(front)) {step[front] = step[rear]+1; pa[front] = 1; fa[front] = rear; front++;}
for(int i = 9; i <= 18; i++) st[front][i] = st[rear][i+2];
st[front][19] = st[rear][9]; st[front][20] = st[rear][10];
for(int i = 0; i <= 8; i++) st[front][i] = st[rear][i];
if(try_to_insert(front)) {step[front] = step[rear]+1; pa[front] = 2; fa[front] = rear; front++;}
for(int i = 0; i <= 9; i++) st[front][i] = st[rear][i+2];
st[front][10] = st[rear][0]; st[front][11] = st[rear][1];
for(int i = 12; i <= 20; i++) st[front][i] = st[rear][i];
if(try_to_insert(front)) {step[front] = step[rear]+1; pa[front] = 3; fa[front] = rear; front++;}
for(int i = 9; i <= 18; i++) st[front][i+2] = st[rear][i];
st[front][9] = st[rear][19]; st[front][10] = st[rear][20];
for(int i = 0; i <= 8; i++) st[front][i] = st[rear][i];
if(try_to_insert(front)) {step[front] = step[rear]+1; pa[front] = 4; fa[front] = rear; front++;}
rear++;
}
}
void print_path(int cur)
{
if(!cur) return;
print_path(fa[cur]);
printf("%d",pa[cur]);
}
void back_print_path(int cur)
{
if(!cur) return;
if(back_pa[cur]==1)printf("3");
else if(back_pa[cur]==3)printf("1");
else if(back_pa[cur]==2)printf("4");
else if(back_pa[cur]==4)printf("2");
back_print_path(back_fa[cur]);
}
int main ()
{
int t;
scanf("%d",&t);
bfs(_aim,-1);
memcpy(back_head,head,sizeof(head));
memcpy(back_next,next,sizeof(next));
memcpy(back_fa,fa,sizeof(fa));
memcpy(back_pa,pa,sizeof(pa));
memcpy(back_st,st,sizeof(st));
while(t--)
{
for(int i = 0; i < 24; i++) scanf("%d",&sta[i]);
if(is_ok()) { puts("PUZZLE ALREADY SOLVED"); continue; }
ans = ans2 = 0; ok = 0; bfs(sta,1);
if(ok) { print_path(ans); back_print_path(ans2); printf("\n");}
else puts("NO SOLUTION WAS FOUND IN 16 STEPS");
}
return 0;
}