549-广度优先遍历搜索迷宫路径-求最短路径

寻找迷宫最短路径

在迷宫里面怎么找最短的路径???
在这里插入图片描述

使用广度遍历迷宫路径搜索最短路径:

0 0 1 1 1 1
1 0 0 0 0 1
1 0 1 1 0 1
1 0 0 0 0 1
1 0 1 1 1 1
1 0 0 0 0 0

广度优先遍历求最短路径

在这里插入图片描述
如果(0,0)的值为1,则表示迷宫的路口是封住的,直接return掉。
如果(0,0)的值为0,则表示路口是通的,把0入队。
然后开启循环,如果队列不为空,看队头元素,它的右边能不能走,能走,则把右边元素入队,
在这里插入图片描述

然后还要看(0,0)元素的下边,左边,上边能不能走,不能走,这个(0,0)元素看处理完了,出队。
在这里插入图片描述

然后现在队头就是第一行的第二个元素了,然后先把它的左边,和(0,0)的右边修改为不能走,然后看这个元素右边能不能走,不能走,看下面能不能走,可以走,然后下面的元素就入队。
在这里插入图片描述

然后队头元素还要看它的左边能不能走,不能走,上面能不能走,不能走,然后处理完了,就出队。

在这里插入图片描述
此时的这个节点就是第二行第二个节点
然后看它右边能不能走,能走,右边元素入队。
在这里插入图片描述

现在新元素是队列的队尾。队头即原来的元素还要继续判断,把所有的方向能走的元素都入队,现在看它的下面能不能走,可以走,下面的元素也入队,
在这里插入图片描述
然后看左边能不能走,不能走,上面能不能走,不能走,然后出队。
在这里插入图片描述
现在的队头元素的第二行第三列的那个元素。队尾元素是第三行第二列的那个元素。
然后继续看队头元素,看它右边能不能走,能走,右边元素入队
在这里插入图片描述
它的下面,左边,上面都不能走。如果把这个队头元素出队。
在这里插入图片描述

现在的队头就是第三行的第二列元素,队尾元素就是第二行第四列的元素。
以此类推下去。
层层扩张
在这里插入图片描述
在队列里,当把一个节点入队以后,我们发现这个队尾元素如果就是右下角的节点,就证明迷宫通路了,走到右下角的节点了。
队列里记录的是所有节点的行走状态,但是前面节点已经出队了,不在队列中。
这个队列存在的问题的:
在这里插入图片描述

队列只能找最短路径。但是最短路径的路径信息记录不下来。
在这里插入图片描述
开辟多大的空间呢?我们只能使用最坏情况下的空间的大小去开辟。
开辟 行乘以列 的大小的数组
在这里插入图片描述
我们到达右下角的节点的时候,就是找到出口了,我们得在迷宫路径有哪些节点,我们要记录右下角的节点是从它左边这个节点过来的,怎么记录?
迷宫是二维数组,在内存上其实都是一维数组,所以我们把这个二维数组映射到下面这个一维数组当中。
在这里插入图片描述
二维数组映射到一维数组的下标的公式如下:
在这里插入图片描述
然后当前节点向哪个方向走,把这个信息记录一下,记在它要走到的那个节点对应的一维数组位置上,记录:当前节点是哪个节点来的。然后一直往前推,直到找到入口节点(0,0),最短迷宫路径的路径信息就出来了。
在这里插入图片描述

代码实现

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

//定义方向
const int RIGHT = 0;
const int DOWN = 1;
const int LEFT = 2;
const int UP = 3;
const int WAY_NUM = 4;

//定义行走状态
const int YES = 4;
const int NO = 5;

//迷宫
class Maze
{
public:
	Maze(int row, int col)
		:_row(row)
		, _col(col)
	{
		_pMaze = new Node*[_row];//开辟迷宫二维数组 
		for (int i = 0; i < _row; ++i)
		{
			_pMaze[i] = new Node[_col];
		}

		//node._x*_row + node._y
		_pPath.resize(_row * _col);//辅助数组开辟空间 
	}

	void initNode(int x, int y, int val)//初始化为No 
	{
		_pMaze[x][y]._x = x;
		_pMaze[x][y]._y = y;
		_pMaze[x][y]._val = val;
		for (int i = 0; i < WAY_NUM; ++i)
		{
			_pMaze[x][y]._state[i] = NO;
		}
	}

	void setNodeState()//设置迷宫行走状态 
	{
		for (int i = 0; i < _row; ++i)
		{
			for (int j = 0; j < _col; ++j)
			{
				if (_pMaze[i][j]._val == 1)
				{
					continue;
				}

				if (j < _col - 1 && _pMaze[i][j + 1]._val == 0)
				{
					_pMaze[i][j]._state[RIGHT] = YES;
				}

				if (i < _row - 1 && _pMaze[i + 1][j]._val == 0)
				{
					_pMaze[i][j]._state[DOWN] = YES;
				}

				if (j > 0 && _pMaze[i][j - 1]._val == 0)
				{
					_pMaze[i][j]._state[LEFT] = YES;
				}

				if (i > 0 && _pMaze[i - 1][j]._val == 0)
				{
					_pMaze[i][j]._state[UP] = YES;
				}
			}
		}
	}

	void searchMazePath()//广度优先遍历搜索 
	{
		if (_pMaze[0][0]._val == 1)
		{
			return;
		}
		_queue.push(_pMaze[0][0]);//入口节点入队 

		while (!_queue.empty())//队列不为空 
		{
			Node front = _queue.front();//获取队头元素 
			int x = front._x;
			int y = front._y;

			//右方向
			if (_pMaze[x][y]._state[RIGHT] == YES)
			{
				_pMaze[x][y]._state[RIGHT] = NO;
				_pMaze[x][y + 1]._state[LEFT] = NO;
				//在辅助数组中记录一下节点的行走信息
				_pPath[x*_row + y + 1] = _pMaze[x][y];
				_queue.push(_pMaze[x][y + 1]);
				if (check(_pMaze[x][y + 1]))
					return;
			}

			//下方向
			if (_pMaze[x][y]._state[DOWN] == YES)
			{
				_pMaze[x][y]._state[DOWN] = NO;
				_pMaze[x + 1][y]._state[UP] = NO;
				_pPath[(x + 1)*_row + y] = _pMaze[x][y];
				_queue.push(_pMaze[x + 1][y]);
				if (check(_pMaze[x + 1][y]))
					return;
			}

			//左方向
			if (_pMaze[x][y]._state[LEFT] == YES)
			{
				_pMaze[x][y]._state[LEFT] = NO;
				_pMaze[x][y - 1]._state[RIGHT] = NO;
				_pPath[x*_row + y - 1] = _pMaze[x][y];
				_queue.push(_pMaze[x][y - 1]);
				if (check(_pMaze[x][y - 1]))
					return;
			}

			//上方向
			if (_pMaze[x][y]._state[UP] == YES)
			{
				_pMaze[x][y]._state[UP] = NO;
				_pMaze[x - 1][y]._state[DOWN] = NO;
				_pPath[(x - 1)*_row + y] = _pMaze[x][y];
				_queue.push(_pMaze[x - 1][y]);
				if (check(_pMaze[x - 1][y]))
					return;
			}

			//当前节点出队列
			_queue.pop();
		}
	}

	void showMazePath()//打印迷宫 
	{
		if (_queue.empty())
		{
			cout << "不存在一条迷宫路径!" << endl;
		}
		else
		{
			//回溯寻找迷宫路径节点
			int x = _row - 1;
			int y = _col - 1;
			for (;;)
			{
				_pMaze[x][y]._val = '*';
				if (x == 0 && y == 0)
					break;
				Node node = _pPath[x*_row + y];
				x = node._x;
				y = node._y;
			}

			for (int i = 0; i < _row; ++i)
			{
				for (int j = 0; j < _col; ++j)
				{
					if (_pMaze[i][j]._val == '*')
					{
						cout << "* ";
					}
					else
					{
						cout << _pMaze[i][j]._val << " ";
					}
				}
				cout << endl;
			}
		}
	}
private:
	//定义迷宫节点路径信息
	struct Node
	{
		int _x;
		int _y;
		int _val;//节点的值
		int _state[WAY_NUM];//记录节点四个方向的状态
	};

	//检查是否是右下角的迷宫出口节点
	bool check(Node &node)
	{
		return node._x == _row - 1 && node._y == _col - 1;
	}

	Node **_pMaze;//动态开辟二维数组 
	int _row;//行 
	int _col;//列 
	queue<Node> _queue;//广度遍历依赖的队列结构
	vector<Node> _pPath;//记录广度优先遍历时,节点的行走信息,辅助数组 
};

int main()
{
	cout << "请输入迷宫的行列数(例如:10 10):";
	int row, col, data;
	cin >> row >> col;

	Maze maze(row, col);//创建迷宫对象

	cout << "请输入迷宫的路径信息(0表示可以走,1表示不能走):" << endl;
	for (int i = 0; i < row; ++i)
	{
		for (int j = 0; j < col; ++j)
		{
			cin >> data;
			//可以初始化迷宫节点的基本信息
			maze.initNode(i, j, data);
		}
	}

	//开始设置所有节点的四个方向的状态
	maze.setNodeState();

	//开始从左上角搜索迷宫的路径信息了
	maze.searchMazePath();

	//打印迷宫路径搜索的结果
	maze.showMazePath();

	return 0;
}

在这里插入图片描述

### 回答1: 广度优先遍历可以用来寻找迷宫中的路径。下面是一个示例代码: ```python from queue import Queue def bfs(maze, start, end): queue = Queue() visited = set() queue.put(start) visited.add(start) path = {} path[start] = None while not queue.empty(): current = queue.get() if current == end: break for neighbor in get_neighbors(maze, current): if neighbor not in visited: queue.put(neighbor) visited.add(neighbor) path[neighbor] = current return get_path(path, start, end) def get_neighbors(maze, cell): neighbors = [] rows, cols = len(maze), len(maze[0]) row, col = cell if row > 0 and maze[row-1][col] == 0: neighbors.append((row-1, col)) if row < rows-1 and maze[row+1][col] == 0: neighbors.append((row+1, col)) if col > 0 and maze[row][col-1] == 0: neighbors.append((row, col-1)) if col < cols-1 and maze[row][col+1] == 0: neighbors.append((row, col+1)) return neighbors def get_path(path, start, end): current = end result = [] while current != start: result.append(current) current = path[current] result.append(start) result.reverse() return result ``` 其中,`maze` 是一个二维数组,表示迷宫,其中 0 表示可通过的格子,1 表示障碍物。`start` 和 `end` 分别表示起点和终点。 函数首先创建一个队列 `queue` 和一个集合 `visited`,将起点加入队列和集合中。然后创建一个字典 `path`,用于记录每个格子的前驱格子。接着进入循环,直到队列为空或者找到终点为止。每次从队列中取一个格子 `current`,并遍历它的相邻格子,如果相邻格子是可通过的且没有被访问过,则将其加入队列和集合中,并在 `path` 中记录它的前驱格子为 `current`。 最后,调用 `get_path` 函数获取从起点到终点的路径。`get_path` 函数从终点开始,沿着 `path` 中记录的前驱格子一路向前,直到到达起点为止。 ### 回答2: 广度优先遍历是一种图的遍历算法,用于寻找迷宫中的路径。在迷宫中,我们可以将每个格子看作一个节点,相邻的格子之间存在着边。迷宫中通畅的路径就是从起始节点到目标节点的一条有效路径广度优先遍历算法的基本思想是从起始节点开始,依次访问其所有相邻的节点,并将这些节点依次加入一个队列中。然后再从队列头取下一个节点进行访问,直到找到目标节点或者队列为空。 具体实现迷宫路径广度优先遍历可以按照以下步骤进行: 1. 创建一个队列,将起始节点加入队列中。 2. 创建一个visited集合,用于记录已经访问过的节点。 3. 创建一个prev字典,用于记录每个节点的前驱节点,即每个节点是从哪个节点遍历而来。 4. 对于队列不为空的情况,重复以下步骤: - 从队列头取一个节点作为当前节点。 - 如果当前节点是目标节点,则停止遍历,此时可以通过prev字典生成迷宫路径。 - 否则,将当前节点标记为已访问,并遍历其所有相邻的节点: - 如果相邻节点没有被访问过,则将其加入队列,并将当前节点设置为其前驱节点。 5. 如果队列为空,但仍未找到目标节点,则说明迷宫中不存在可到达目标节点的路径。 通过广度优先遍历,我们可以找到从起始节点到目标节点的最短路径,因为遍历过程中,第一次访问到目标节点时,一定是经过的路径最短的。使用prev字典即可回溯路径。 ### 回答3: 广度优先遍历是一种图的搜索算法,可以用于解决迷宫路径的问题。迷宫可以看作是一个由行和列组成的二维矩阵,其中的每个元素可以是墙壁、通路或终点。 广度优先遍历利用队列来实现,从起点开始,将起点入队,并将其标记为已访问。然后,不断从队列中取元素,并检查其周围的相邻节点是否可访问。如果可访问,则将其入队,并标记为已访问。直到队列为空为止,即找到了终点或者无法找到路径。 具体实现时,可以使用一个二维数组来表示迷宫,其中的元素值表示该位置的状态(0表示墙壁,1表示通路,2表示终点)。另外,可以使用一个二维数组来记录每个位置的步数,初始值为0。 首先,将起点入队,并将起点的步数设置为1。然后,进入循环,直到队列为空。在循环中,从队列中取一个节点,再枚举其四个相邻节点(上、下、左、右)。对于每个相邻节点,如果该节点可访问且未被访问过,则将其入队,并将其步数设置为当前节点的步数加1。同时,标记该位置为已访问。如果某个相邻节点的值为2,则说明找到了终点,此时可退循环。 最后,可以通过回溯的方式,从终点开始,沿着步数递减的路径依次找到起点,并将路径上的位置存入一个栈中。最后,将栈中的元素依次栈,即可得到起点到终点的路径。 总结起来,广度优先遍历实现迷宫路径的步骤如下: 1. 将起点入队,并将其标记为已访问。 2. 进入循环,直到队列为空。 - 从队列中取一个节点。 - 枚举其四个相邻节点。 - 如果相邻节点可访问且未被访问过,将其入队,并将其步数设置为当前节点的步数加1。同时,标记该位置为已访问。 - 如果某个相邻节点的值为2,退循环。 3. 通过回溯的方式,找到起点到终点的路径,并存入一个栈中。 4. 将栈中的元素依次栈,得到起点到终点的路径。 通过以上步骤,就可以使用广度优先遍历找到迷宫路径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值