zoukankan      html  css  js  c++  java
  • 利用非循环顺序队列采用广度搜索法求解迷宫问题(一条路径)

    // algo3-11.cpp 利用非循环顺序队列采用广度搜索法求解迷宫问题(一条路径)
    #include"c1.h"
    #include"func3-1.cpp"
    #define D 8 // 移动方向数,只能取4和8。(8个,可斜行;4个,只可直走)
    typedef struct // 定义队列元素和栈元素为同类型的结构体(见图3.38)
    {
    	PosType seat; // 当前点的行值,列值
    	int pre; // 前一点在队列中的序号
    }QElemType,SElemType; // 栈元素和队列元素
    #include"c3-1.h" // 栈的存储结构
    #include"bo3-1.cpp" // 栈的基本操作
    #include"c3-4.h" // 队列的存储结构
    #include"bo3-4.cpp" // 非循环顺序队列的基本操作(1)
    //#include"bo3-9.cpp" // 非循环顺序队列的基本操作(2)
    struct // 移动数组,移动方向由正东起顺时针转
    {
    	int x,y;
    }move[D]={
    #if D==8
    	{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
    #endif
    #if D==4
    	{0,1},{1,0},{0,-1},{-1,0}};
    #endif
    	void Path()
    	{ // 广度搜索法求一条迷宫路径
    		SqQueue2 q; // 采用非循环顺序队列
    		QElemType qf,qt; // 当前点和下一点
    		SqStack s; // 采用顺序栈
    		int i,flag=1; // 当找到出口,flag=0
    		qf.seat.x=begin.x; // 将入口作为当前点
    		qf.seat.y=begin.y;
    		qf.pre=-1; // 设入口(第一点)的上一点的序号=-1
    		m[qf.seat.x][qf.seat.y]=-1; // 初始点设为-1(标记已访问过)
    		InitQueue(q);
    		EnQueue(q,qf); // 起点入队
    		while(!QueueEmpty(q)&&flag)
    		{ // 队列中还有没被广度搜索过的点且还没找到出口
    			DeQueue(q,qf); // 出队qf为当前点
    			for(i=0;i<D;i++) // 向各个方向尝试
    			{
    				qt.seat.x=qf.seat.x+move[i].x; // 下一点的坐标
    				qt.seat.y=qf.seat.y+move[i].y;
    				if(m[qt.seat.x][qt.seat.y]==1)
    				{ // 此点是通道且不曾被访问过
    					m[qt.seat.x][qt.seat.y]=-1; // 标记已访问过
    					qt.pre=q.front-1; // qt的前一点处于队列中现队头减1的位置(没删除)
    					EnQueue(q,qt); // 入队qt
    					if(qt.seat.x==end.x&&qt.seat.y==end.y) // 到达终点
    					{
    						flag=0;
    						break;
    					}
    				}
    			}
    		}
    		if(flag) // 搜索完整个队列还没到达终点
    			printf("没有路径可到达终点!
    ");
    		else // 到达终点
    		{
    			InitStack(s); // 初始化s栈
    			i=q.rear-1; // i为待入栈元素在队列中的位置
    			while(i>=0) // 没到入口
    			{
    				Push(s,q.base[i]); // 将队列中的路径入栈(栈底为出口,栈顶为入口)
    				i=q.base[i].pre; // i为前一元素在队列中的位置
    			}
    			i=0; // i为走出迷宫的足迹
    			while(!StackEmpty(s))
    			{
    				Pop(s,qf); // 依照由入口到出口的顺序弹出路径
    				i++;
    				m[qf.seat.x][qf.seat.y]=i; // 标记路径为足迹(标记前的值为-1)
    			}
    			printf("走出迷宫的一个方案:
    ");
    			Print(); // 输出m数组
    		}
    	}
    	void main()
    	{
    		Init(1); // 初始化迷宫,通道值为1
    		Path(); // 求一条迷宫路径
    	}

    代码的运行结果:


    algo3-11.cpp 也是一种求迷宫的算法。该算法先将入口坐标及-1 入队,-1 表示入口坐
    标是第1 点(无前驱)。出队入口点(1,1,-1),找m[1][1]周边值为1 的点(m[1][2]和
    m[2][1]),入队这2 点,且令它们的pre 成员值为0,因为它们的前一步是m[1][1],而
    m[1][1] 在队列中的序号为[0] ; 再出队(1,2,0) , 找m[1][2] 周边值为1 的点
    (m[1][3]),入队该点,且令它的pre 成员值为1;⋯⋯;直到入队(3,3,4)。而m[3][3]
    恰是出口,说明找到了一条由入口到出口的路径。为了输出这条路径,将(3,3,4)入栈s,
    由(3,3,4)得知,出口的前一步在队列中序号为[4]处。再入栈队列中序号为[4]的元素
    (3,2,2)。依此类推,再入栈队列中序号为[2]的元素(2,1,0)、序号为[0]的元素(1,1,-1)。
    出栈s 时,依次将m[1][1]、m[2][1]、m[3][2]和m[3][3]赋值1、2、3 和4(足迹)。
    在到达终点时,队列的状态如图339(a)所示。这时队列中只有2 个元素,队头元素
    的序号为[5],队尾元素的序号为[6]。序号从[0]到[4]的那些元素虽然出队,但它们在队
    列中的存储状态并没有遭到破坏,仍完好地保存。所以才可以调出队列的“历史记录”。
    这也算是这种存储结构的一个优点吧。

    在algo3-11.cpp 的第4 行,我们定义D 为8,它可以斜行(从足迹2 到足迹3)。如果
    定义D 为4,输入相同,则需4 步走到出口。运行结果如下(省略相同部分):


  • 相关阅读:
    Kafka Eagle安装
    CentOS下OpenJDK设置JAVA_HOME
    设计模式:解释器模式
    Typora主题推荐
    SpringMVC的<mvc:annotation-driven />
    SpringMVC的视图解析器
    数字化营销
    《计算广告》第二版思维导图
    舆情计算
    实时数仓
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/3945958.html
Copyright © 2011-2022 走看看