ACM之八数码问题----BFS搜索----数独游戏的模拟(下)
题目描述;数独游戏的内核代码
八数码问题;
编号为1到8的8个正方形滑块被摆成3行3列;(有一个格子留空);
每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中;
而它原来的位置就成为了新的空格;给定初始局面和目标局面(用0表示空格);
你的任务死计算出最少的移动步数;和移动过程;如果无法到达目标局面,则输出-1;
------------------------------------------------------------------------------
接前面两个博客,在这个博客里,我们尝试改变我们使用的判重的数据结构;在第一个博客里我们用的是
数组,也就是顺序结构,速度非常的慢,在第二个博客里我们使用是c++里的set类库,其结构是一种特殊的红黑树
同时使用,整数来存储状态,加快了速度,体现了选择正确的数据结构的重要性,在本博客里,展示的是使用哈希技术实现的随机访问;
随机访问,也就是下标访问法;速度很快;
#include <iostream> #include <fstream> using namespace std; #include <stdio.h> #include <stdlib.h> #include <string.h>//因为这里要用到memcmp和memcpy函数; //这两个函数比我们写的循环效率要高; #define MAX 1000000 //为什么选择这么大呢?排列数9!; typedef struct Node { int state[9];//存放本状态各个位置的数码值; int fa;//记录父节点的下标; int deepth; int last_x; int last_y; }Node; Node q[MAX];//构成状态数组; int head[MAX]; int hash_next[MAX]; const int dx[4]={-1,1,0,0};//左右上下; const int dy[4]={0,0,-1,1}; int bfs();//广度优先找到目标状态; void print_path(int founded);//根据fa成员,通过递归技术实现状态依次输出; Node destination;//存储目标状态; int i,j,k; int main() { /*首先输入起始状态和目标状态;*/ memset(q,0,sizeof q); for(i=0;i<9;i++) { scanf("%d",&(q[0].state[i])); } for(i=0;i<9;i++) { scanf("%d",&destination.state[i]); } memset(head,0,sizeof head); memset(hash_next,0,sizeof hash_next); /*然后进行搜索并输出;*/ int founded=bfs(); if(founded) { printf("%d\n",q[founded].deepth); print_path(founded); } else printf("-1\n"); system("pause"); return 0; } int bfs() { int front=1,rear=2;//用来模拟队列的先进先出,达到广度优先的目的; int v=0; q[1].deepth=0; q[1].fa=1; for(k=0;k<9;k++) { v=10*v+q[front].state[k]; } v=v%MAX; head[v]=1; while (front<rear) { Node &first=q[front]; if (memcmp(first.state,destination.state,sizeof destination.state)==0) {//找到了目标状态; return front; } for(i=0;i<9;i++) if (!first.state[i]) {//找到空格处; break; } for(j=0;j<4;j++) {//向四个方向进行转换; Node &new_Node=q[rear]; memcpy(new_Node.state,first.state,sizeof first.state); int new_x=i%3+1+dx[j]; int new_y=i/3+1+dy[j]; if (new_x>0&&new_y>0&&new_x<4&&new_y<4) { //位置合法; new_Node.state[i]=new_Node.state[i+dx[j]+3*dy[j]];//空格位置; new_Node.state[i+dx[j]+3*dy[j]]=0;//新的状态形成了; v=0; for(k=0;k<9;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的; { v=10*v+new_Node.state[k]; } v=v%MAX; int u=head[v]; int found=0; while(u) { if(memcmp(q[u].state,new_Node.state,sizeof new_Node.state)==0) { found=1; break; } u=hash_next[u]; } if(!found)//没有被访问; { new_Node.fa=front; new_Node.deepth=first.deepth+1; new_Node.last_x=dx[j]; new_Node.last_y=dy[j]; hash_next[rear]=head[v]; head[v]=rear; rear++; }//if }//if }//for front++; //printf("%d %d\n",front,q[front].deepth); }//while return 0; } void print_path(int founded) { if(q[founded].fa!=founded) { print_path(q[founded].fa); } for(i=0;i<3;i++) { for(j=0;j<3;j++) { printf("%d ",q[founded].state[3*i+j]); } printf("\n"); } printf("\n"); }
这里使用了哈希技术,把状态进行操作,使其作为下标;这样就能不受数组大小的限制,马上访问到对应的状态;
哈希表的执行效率高,适用的范围很广,可以快速的查找;
作者:在河之博
出处:http://www.cnblogs.com/dragonfive/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。