八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
#include "stdio.h"
#include "string.h"
//八数码问题
typedef int State[9];//表示一个状态
#define MAX 500000
State states[MAX];
State gold;//目标状态
int distance[MAX];//距离数组
int head[MAX];
int next[MAX];
//散列函数(hash函数)
int hash (State * s) {
int sum = 0;
int i;
for (i = 0;i < 9;i++) {
sum = sum *10 + (*s)[i];
}
return sum % MAX;
}
int lookup (State *s,int pos) {
int h = hash (s);
int u = head[h];
while (0 != u) {
if (memcmp(*s,states[u],sizeof(states[u])) == 0) {//插入失败
return 0;
}
u = next[u];
}
next[pos] = head[h];
head[h] = pos;
return 1;
}
const int dir_x[] = {-1,1,0,0};
const int dir_y[] = {0,0,-1,1};
int bfs () {
int front = 0;
int tail = 1;
int i;
int z;
int x,y,new_x,new_y,new_z;
distance[front] = 0;
memset (head,0,sizeof(head));
while (front < tail) {
State *s = &states[front];
if (memcmp(*s,gold,sizeof(gold)) == 0) {
return front;
}
for (i = 0;i < 9;i++) {//确定0的位置
if ((*s)[i] == 0) {
z = i;
break;
}
}
x = z / 3;
y = z % 3;
for (i = 0;i < 4;i++) {
new_x = x + dir_x[i];
new_y = y + dir_y[i];
new_z = new_x * 3 + new_y;
if (new_x >= 0 && new_x < 3 && new_y >=0 && new_y < 3) {//移动方向是否合法
State st;
int result;
memcpy (st,*s,sizeof(st));
st[z] = (*s)[new_z];
st[new_z] = 0;
result = lookup(&st,tail);
if (result) {
int k;
memcpy (states[tail],st,sizeof((states[tail])));
/*
for (k = 0;k < 9;k++) {
printf ("%d ",states[tail][k]);
}
printf ("\n");
*/
distance[tail] = distance[front] + 1;
tail++;
}
}
}
front++;
}
return -1;
}
int main () {
int i;
int result;
// freopen("d:/input.xt","wr",stdout);
for (i = 0;i < 9;i++) {
scanf("%d",&states[0][i]);
}
for (i = 0;i < 9;i++) {
scanf ("%d",&gold[i]);
}
result = bfs ();
if (result != -1) {
printf ("%d\n",distance[result]);
}else {
printf ("-1\n");
}
return 0;
}