在BFS的时候使用链表实现的哈希表记录vis判重
sample input:
2 6 4
1 3 7
0 5 8
8 1 5
7 3 6
4 0 2
sample output:
31
无法到达目标局面输出 -1
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef int State[9];
const int maxstate=1000000;
State st[maxstate],goal;
//State是一个int[9]的类型 int st[maxstate][9];
int dist[maxstate];
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int hashsize=1000003;
int head[hashsize], next[maxstate];
void init_lookup_table(){ memset(head,0,sizeof(head)); }
int hash_f(State &s){
int v=0;
for(int i=0;i<9;i++) v=v*10+s[i]; //将9个数字的位置组合成一个9位数
return v % hashsize; //确保hash函数值是不超过hash表大小的非负整数
}
int try_to_insert(int s){ //尝试插入hash表要把hash值相同的状态组织成链表
int h=hash_f(st[s]); //获取该结点的hash值
int u=head[h]; //从表头开始查找链表
while(u){ //存在哈希冲突
if(memcmp(st[u],st[s],sizeof(st[s]))==0)return 0; //找到了,插入失败,该结点已被扩展
u=next[u]; //顺着链表继续找
}
next[s]=head[h]; //插入到链表中
head[h]=s; //更新表头
return 1;
}
int bfs(){
init_lookup_table();
int frnt=1, rear=2; //不使用下标0,因为0被看做不存在
while(frnt<rear){
State& s=st[frnt];
if(memcmp(goal,s,sizeof(s))==0) return frnt; //找到目标状态,成功返回
int z;
for(z=0;z<9;z++) if(!s[z])break; //z是 "0" 的位置
int x=z/3,y=z%3;
for(int d=0;d<4;d++){
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*3+newy; //进行移动后 "0" 的新位置
if(newx>=0&&newx<3&&newy>=0&&newy<3){
State& t=st[rear];
memcpy(&t,&s,sizeof(s)); //扩展新结点
t[newz]=s[z];
t[z]=s[newz]; //移动操作即为将 "0" 和目标方块互换
dist[rear]=dist[frnt]+1; //更新新结点的距离值
if(try_to_insert(rear))rear++; //插入hash表成功,修改队尾指针
}
}
frnt++; //该父结点的子节点扩展完毕后修改队首指针
}
return 0; //bfs失败,无法到达目标状态
}
int main (){
//freopen("datain.txt","r",stdin);
for(int i=0;i<9;i++)scanf("%d",&st[1][i]);
for(int i=0;i<9;i++) scanf("%d",&goal[i]);
int ans=bfs(); //返回目标状态的编号
if(ans>0)printf("%d\n",dist[ans]);
else printf("-1\n"); //返回0,则无法到达目标状态
return 0;
}