代码部分源自于算法入门经典,略微做了些修改。算法核心采用了bfs,但是在判断当前状态是否已经访问过时,之前试过遍历0-rear范围内bufs数组内的状态进行比较,但是太慢了,后来看了这个hash的办法,很好用。算法稍微做些添加,便可以输出一条搜索路径,这里没有给出实现。
#include <stdio.h>
#include <string.h>
#define maxn 1000000
#define maxhashsize 1000003
#define len 9*sizeof(int)
int bufs[maxn][9], goal[9], front, rear;
int head[maxhashsize], next[maxhashsize];
int d[maxn];
int fa[maxn];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int hashfunc(){
int i, sum = 0, *t = &bufs[rear][0];
for(i = 0; i < 9; ++i) sum =sum*10 + t[i];
return sum%maxhashsize;
}
int try_to_insert(){
int *p, *t = &bufs[rear][0];
int h = hashfunc();
int u = head[h];
while(u){
p = &bufs[u][0];
if(memcmp(t, p, len) == 0) return 0;
u = next[u];
}
next[rear] = head[h];
head[h] = rear;
return 1;
}
void init_lookup_table(){
memset(head, 0, sizeof(head));
int h = hashfunc();
try_to_insert();
}
int bfs(){
int *tmp;
front = 1; rear = 1;
init_lookup_table();
rear = 2;
d[front] = 0;
fa[front] = 0;
while(front < rear){
tmp = &bufs[front][0];
if(memcmp(tmp, goal, len) == 0) return front;
int i, j, z;
for(z = 0; z < 9; ++z) if(!tmp[z]) break;
int x = z / 3, y = z % 3;
for(i = 0; i < 4; ++i){
int newx = x + dx[i];
int newy = y + dy[i];
if(newx>=0 && newy>=0 && newx<3 && newy<3)
j = 3*newx + newy;
else
continue;
int *t = &bufs[rear][0];
memcpy(t, tmp, len);
t[j] = tmp[z];
t[z] = tmp[j];
d[rear] = d[front] + 1;
fa[rear] = front;
if(try_to_insert()) ++rear;
}
++front;
}
return 0;
}
int main(){
/*2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
d = 31*/
int i;
for(i = 0; i < 9; ++i) scanf("%d", &bufs[1][i]);
for(i = 0; i < 9; ++i) scanf("%d", &goal[i]);
if(bfs())
printf("%d\n", d[front]);
else
printf("-1\n");
return 0;
}