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

}

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

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

你可能感兴趣的:(ACM)