解八数码问题。
/*编号为1-8的8个正方形滑块被摆成3行3列(空一格), 每次可以把与空格相邻的滑块移到空格中! 而它原来的位置就变成了空格! 任务就是计算出最少的移动步数,如果无法移动到目标局面,就输出-1! */ #include<cstdio> #include<iostream> #include<cstring> using namespace std; const int maxn=1001314; int dx[4]= {1,0,-1,0}; int dy[4]= {0,1,0,-1}; int head[maxn],next[maxn],dis[maxn]; typedef int A[9]; A aa[maxn],goal; void init() { memset(head,0,sizeof(head)); } int hash(A& s) { int sum=0; for(int i=0; i<9; i++) { sum=sum*10+s[i]; }//把九个数组合成9位数 return sum%maxn;//确保hash函数值是不超过hash表的大小的非负整数 } bool insert(int s)//使用哈希表、 { int h=hash(aa[s]);//从表头开始查找链表 int u=head[h]; while(u) { if(memcmp(aa[u],aa[s],sizeof(aa[s]))==0) return false;//找到了,插入失败 u=next[u];//顺着链表继续找 } next[s]=head[h];//插入到链表中 head[h]=s; return true; } int bfs() { init();//初始化 int begin=1,end=2; while(begin<end) { A& now=aa[begin]; if(memcmp(now,goal,sizeof(now))==0)//如果找到最终状态,则返回最终状态的下标。 return begin; int point; for(point=0; point<9; point++) if(now[point]==0)//找到0所在的编号 break; for(int i=0; i<4; i++) { int x=point/3,y=point%3; int new_x=x+dx[i]; int new_y=y+dy[i]; int new_point=new_x*3+new_y;//新滑块的编号 if(new_x>=0&&new_y>=0&&new_x<3&&new_y<3) {//如果没有越出边界 A& te=aa[end]; memcpy(&te,&now,sizeof(now)); te[point]=now[new_point]; te[new_point]=now[point]; //交换新滑块和空格的位置,即编号 dis[end]=dis[begin]+1;//更新步数。 if(insert(end)) end++; } } begin++; } return 0;//没有办法变成最终状态 } int main() { for(int i=0; i<9; i++) cin>>aa[1][i];//起始状态 for(int i=0; i<9; i++) cin>>goal[i];//最终状态 int ans=bfs();//返回最终状态的下标 if(ans>0) cout<<dis[ans]<<endl; else cout<<-1<<endl; return 0; } /* 2 6 4 1 3 7 0 5 8 8 1 5 7 3 6 4 0 2 */
原文地址:http://blog.csdn.net/u014004096/article/details/42713379