zoukankan      html  css  js  c++  java
  • 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");
    }
    

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

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

  • 相关阅读:
    leetcode 416. Partition Equal Subset Sum
    leetcode 696. Count Binary Substrings
    leetcode 74. Search a 2D Matrix
    leetcode 199. Binary Tree Right Side View
    leetcode 43. Multiply Strings
    leetcode 695. Max Area of Island
    leetcode 257. Binary Tree Paths
    leetcode 694. Number of Distinct Islands
    ros使用时的注意事项&技巧2
    ros使用时的注意事项&技巧
  • 原文地址:https://www.cnblogs.com/dragonfive/p/2979583.html
Copyright © 2011-2022 走看看