迷宫问题,可以用队列找到所有路径么?c/c++描述

使用队列遍历迷宫所有路径
本文探讨了如何使用队列寻找迷宫的所有路径,而非仅找到最短路径。通过理解路径形成的条件,即遇到空格可前进且避免重复路径,可以实现队列在迷宫问题中的应用。在队列中,不进行回溯,而是不断检查新方格并入队,直至找到所有路径。最终给出了实现这一方法的C++代码示例。

  本号最近总结过关于迷宫问题的多种解法,栈啊,递归啊,队列啊。深度优先啊,广度优先啊,最短路径和所有路径。我们知道用栈的方法是可以找到迷宫里从入口到出口的所有路径,用队列可以找到最短路径。那么用队列是否也能找到所有路径呢?
  答案是可以的。以前我认为不可以,因为对比栈的查找所有路径,找到一条路径后,要进行退栈,回溯,同时把退栈的空格(迷宫由墙壁和空格组成,空格表示可以走的路径)改为可用,以便别的路径能继续使用这些空格。同时考察路径中的空格是否有剩余的方向也是空格,是否可以加入栈,组成新路径。那么在队列里,我们无法进行类似的回溯。队列数组成员里,我们是保存了每个空格的行列坐标和它前面空格的数组下标,但在队列里,假如进行类似的回溯,那么回溯到哪个下标为止,如何更改空格已走过的标记,如何考察其是否有新的可用方向,新路径里的可用空格入队列后,如何与它前面的空格联系起来?考虑这些因素后,以前我认为队列是广度优先搜索,以找到的第一个路径为最短路径。无法找到所有路径。现在在学习二叉树的层序遍历里,又用到了队列,结合对比分析后,感觉可以用队列输出迷宫的所有路径。
  解决方案是,我们要弄清楚,形成迷宫路径的依据是什么:
  ①遇到墙壁不能入路径,遇到空格可以入路径;
  ②若遇到的空格是路径里已经走过的,也不能入路径,要不就形成死循环了。意思是说只能入队列路径里没走过的新方格。
  如此路径必然能越来越远离起点,最终必然能通过各个可能的方向经过终点,形成所有路径。
  在队列里我们不进行回溯,不像栈那样进行退栈回溯。顺序队列里头下标和尾下标都是一往无前,不后退。尾插入新空格,头下标删除空格,头下标越过空格后,就无法再访问它了,相当于从队列里删除了访问过的方格。
  队列头下标访问队列里每个数组元素,若是终点(比较其行列坐标),则表明找到了一条路径,把路径里所有空格用字符’/‘表示,以在屏幕上显示出这条路径,输出后接着头下标加1,继续核对队列数组里下一元素。(注:队列里保存的都不是墙壁,无论是空格还是被别的路径标记过的’/’,都是可以被本当前路径使用的,只要俩路径不完全重合,就是新路径)。若头下标所指并非终点,就要考察其上下左右是否有相邻的合适的方格(既包括空格,也包括’/’,非墙壁就行),合适就是要求方格不能是路径里已有的。只此一条限定就可以。若新方格合适,则入队列,插在尾下标位置。然后头下标加1,继续核对队列里剩余的所有方格。直到遇到尾下标为止。
  如此以来,整个队列里确实能保存多条路径。头下标查找的过程,就是多条路径同时前进的过程,找到一条路径也不要退出程序。让头下标等于尾下标为止,就必然能遍历到队列里的所有路径。终点方格在队列里出现几次,就是对应几条路径。
  因为对于每条路径,要输出其完整路径。所以我们要保存路径里从起点到终点的每一步。所以,我们不能采用循环队列,意思是队列数组的元素数据不能被破坏,直到头下标遇到尾下标为止。队列建的大一点就可以了。
  每一个新方格入队列都要进行核对,程序的时间复杂度会比较大,但电脑嘛,运算速度贼快,现在不让它表现下贼快的运算速度,还等什么时候呢?反正路径找到就可以了,目标完成了。各位若有更好的方法,欢迎指正,一起学习。
完整代码如下:

#include<iostream>
using namespace std;
#define MAXSIZE 100
struct Step {
	int row;
	int column;
	int indexFront;
};
struct Queue {
	Step step[MAXSIZE];
	int indexHead = 0;
	int indexTail = 0;
};/*
char maze[10][10] = {
	'H','H','H','H','H','H','H','H','H','H',
	'H',' ',' ',' ',' ',' ',' ','H',' ','H',
	'H',' ','H','H','H','H',' ',' ',' ','H',
	'H',' ','H',' ',' ','H','H',' ','H','H',
	'H',' ','H','H',' ',' ',' ',' ',' ','H',
	'H',' ',' ',' ','H','H',' ','H',' ','H',
	'H',' ','H',' ',' ',' ','H',' ',' ','H',
	'H',' ',' ','H','H',' ','H','H',' ','H',
	'H','H',' ',' ',' ',' ',' ',' ',' ','H',
	'H','H','H','H','H','H','H','H','H','H'
};*/

char maze[10][10] = {
	'H','H','H','H','H','H','H','H','H','H',
	'H',' ',' ',' ',' ',' ',' ',' ',' ','H',
	'H',' ','H','H','H','H','H','H',' ','H',
	'H',' ','H',' ',' ',' ',' ',' ',' ','H',
	'H',' ','H',' ','H','H','H','H','H','H',
	'H',' ','H',' ','H',' ',' ',' ',' ','H',
	'H',' ','H',' ',' ',' ','H','H',' ','H',
	'H',' ','H','H','H','H','H','H',' ','H',
	'H',' ',' ',' ',' ',' ',' ',' ',' ','H',
	'H','H','H','H','H','H','H','H','H','H'
};

void printAllPath() {
	maze[1][1] = 'I';
	maze[8][8] = 'O';
	for (int row = 0; row <= 9; row++) {
		for (int column = 0; column <= 9; column++)
			cout << maze[row][column];
		cout << endl;
	}
}
void findAllPath(int inRow, int inColumn, int outRow, int outColumn) {
	Queue queue;
	queue.step[0].row = inRow;
	queue.step[0].column = inColumn; //队列初始化,存入起始点
	queue.step[0].indexFront = -1;

	Step stepNext, stepHead;
	bool checkNextStep;//查看下一个要入队列的点是否可以入队列。若为墙壁H或者为
	//当前路径里已经有的点,则为false,不可以入队。否则可以入队列
	while (queue.indexHead <= queue.indexTail) {
		stepHead = queue.step[queue.indexHead];
		//find the exit pot
		if (stepHead.row == outRow && stepHead.column == outColumn) 
			for (int i = stepHead.indexFront;i > 0;) {
				maze[queue.step[i].row][queue.step[i].column] = '/';
				i = queue.step[i].indexFront;
			}
		else //若indexHead指向终点,直接indexHead++,查找队列里下一个点
		//否则表明indexHead指向的点为路径中间的点,应考察下一个合适的点的坐标
			for (int direction = 0; direction <= 3; direction++) {
				checkNextStep = true;//对于每个待检测方格都要先假设可以入队
				switch (direction) {
				case 0://right
					stepNext.row = stepHead.row;
					stepNext.column = stepHead.column + 1; break;
				case 1://down
					stepNext.row = stepHead.row + 1;
					stepNext.column = stepHead.column; break;
				case 2://left
					stepNext.row = stepHead.row;
					stepNext.column = stepHead.column - 1; break;
				case 3://up
					stepNext.row = stepHead.row - 1;
					stepNext.column = stepHead.column; break;
				}

				if (maze[stepNext.row][stepNext.column] != 'H') {
					//查看stepNext将要进入的路径中是否有与stepNext重合的点
					//否则会使路径陷入死循环
					for (int i = stepHead.indexFront; i >= 0;) {
						if (queue.step[i].row == stepNext.row &&
							queue.step[i].column == stepNext.column) {
							checkNextStep = false;
							break;
						}

						i = queue.step[i].indexFront;
					}

					if (checkNextStep) {
						queue.indexTail++;
						queue.step[queue.indexTail] = stepNext;
						queue.step[queue.indexTail].indexFront = queue.indexHead;
					}
				}
			}
		queue.indexHead++;
	}
}
int main() {
	Step steps[MAXSIZE];
	int inRow = 1, inColumn = 1, outRow = 8, outColumn = 8;
	findAllPath(inRow,inColumn,outRow,outColumn);
	printAllPath();
	return 0;
}

测试的迷宫与测试结果如下:
在这里插入图片描述
在这里插入图片描述






在这里插入图片描述
在这里插入图片描述
谢谢阅读。

问题描述: 以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫出从入口(0,0)到出口(m-1,n-1)的通路和通路总数,或得出没有通路的结论。例如下图, 0(入口) 1 0 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0(出口) 从入口到出口有6条不同的通路。 而下图: 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 1 1 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 1 1 1 0 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 0 0 0 从入口到出口则没有通路。 算法设计: 给定一个m*n的长方阵表示迷宫,设计算法输出入口到出口的通路和通路总数,或得出没有通路的结论。 算法提示: 和皇后问题与分书问题类似。可以用二维数组存储迷宫数据,对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通。从当前位置a(用(x,y)表示一个位置,假定它是以向右的x轴和向下的y轴组成的平面上的一个点)出发依次尝试四个方向是否有路,若某个方向的位置b可通,则按照同样的方法继续从b出发寻找。若到达出口,则找到一条通路。 数据输入: 由文件input.txt 提供输入数据。第一行是m和n的值,空格分隔,其后共m行。每行有n个数字,数和数之间用空格分隔。 结果输出: 将计算出的所有从入口到出口的通路输出到文件output.txt 中。若没有通路,则将0写入文件中。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangzhangkeji

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值