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");
}

这里使用了哈希技术,把状态进行操作,使其作为下标;这样就能不受数组大小的限制,马上访问到对应的状态;

哈希表的执行效率高,适用的范围很广,可以快速的查找;

原文地址:https://www.cnblogs.com/dragonfive/p/2979583.html