迷宫中的最短路径:如何用 BFS 找到最近出口【算法模板】

如何通过广度优先搜索(BFS)求解迷宫问题

在这篇文章中,我们将学习如何使用 广度优先搜索(BFS) 解决一个典型的迷宫问题,具体是从迷宫的一个入口出发,找到最近的出口。我们将一步步分析 BFS 是如何工作的,并展示详细的 C++ 实现代码,帮助你更好地理解算法的原理和细节。

1. 问题描述

假设我们有一个二维迷宫,其中 + 代表墙壁,. 代表空地。迷宫的某些空地可能位于迷宫边缘,作为出口。我们需要找到从迷宫内给定的 入口 到达最近 出口 的最短路径。

  • 输入:迷宫矩阵 maze,以及入口坐标 entrance
  • 输出:从入口到最近出口的步数。如果不存在出口,则返回 -1

1926. 迷宫中离入口最近的出口 - 力扣(LeetCode)

2. 广度优先搜索(BFS)介绍

广度优先搜索 是一种用于搜索树或图的遍历算法,适合用来解决 最短路径问题。BFS 从起始点开始,每次遍历离起始点最近的节点,逐层向外扩展,因此 BFS 保证了找到的第一个解是最短路径。

迷宫问题中的 BFS 思路:

  • 从入口开始进行 BFS,逐步检查四个方向的邻居(上、下、左、右),记录步数。
  • 如果遇到边界上的出口,则返回步数,表示找到最短路径。
  • 如果遍历完整个迷宫没有找到出口,返回 -1

3. BFS 算法的实现步骤

以下是解题的主要步骤:

  1. 初始化数据结构

    • 使用队列(queue)来存储当前要探索的点。
    • 使用 visited 数组标记哪些点已经访问过,防止重复访问。
  2. 方向数组(directions-vector)

    • 使用一个二维向量 directions,存储四个方向的坐标偏移量,分别代表 上、下、左、右。每次我们检查当前点的四个邻居,看看能否向该方向移动。
  3. BFS 主循环

    • 在 BFS 主循环中,每次从队列中取出当前层的节点,逐步遍历它们的四个邻居。
    • 如果某个邻居位于迷宫边界且是空地,我们就找到了出口,返回当前步数。
  4. 层次遍历

    • 每当完成一层的遍历,步数 steps 增加。
  5. 特殊情况处理

    • 需要确保入口不算作出口,避免错误判断。

4. C++ 代码实现

我们通过 C++ 实现这个 BFS 算法,详细注释解释了每个步骤:

#include <vector>
#include <queue>
using namespace std;class Solution {
public:int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {int m = maze.size();    // 行数int n = maze[0].size(); // 列数// 四个方向:上、下、左、右vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};// 初始化队列和 visited 数组queue<pair<int, int>> q;vector<vector<bool>> visited(m, vector<bool>(n, false));// 将入口加入队列并标记为访问过int startX = entrance[0], startY = entrance[1];q.push({startX, startY});visited[startX][startY] = true;// 记录当前的步数int steps = 0;// 开始 BFSwhile (!q.empty()) {int size = q.size();  // 当前层的节点数量// 遍历当前层的每一个节点for (int i = 0; i < size; ++i) {auto [x, y] = q.front();q.pop();// 检查当前点是否是出口(边界上的空格)if ((x == 0 || x == m - 1 || y == 0 || y == n - 1) && !(x == startX && y == startY)) {return steps;}// 向四个方向扩展for (auto [dx, dy] : directions) {int newX = x + dx;int newY = y + dy;// 检查是否可以移动到新的点if (newX >= 0 && newX < m && newY >= 0 && newY < n && maze[newX][newY] == '.' && !visited[newX][newY]) {q.push({newX, newY});visited[newX][newY] = true;  // 标记为已访问}}}steps++;  // 当前层遍历完后步数增加}return -1;  // 如果遍历完迷宫没有找到出口}
};

5. 代码细节讲解

  1. 方向数组(directions

    • directions 数组包含了四个方向的坐标偏移量:上({-1, 0})、下({1, 0})、左({0, -1})、右({0, 1})。这种方法能避免手写多个 if 判断条件,使代码更加简洁。
    • 在 BFS 中,遍历当前点的四个邻居时,我们通过这个方向数组,快速获取新的坐标。
  2. 队列和层次遍历

    • queue<pair<int, int>> q; 是我们使用的队列,它存储了当前层要探索的坐标。
    • 在 BFS 主循环中,每次取出当前层的所有节点,遍历完这一层后步数 steps++
  3. 出口判断

    • 当一个点位于迷宫边界且不是入口时,它就被认为是出口。
  4. 时间复杂度和空间复杂度

    • 时间复杂度:由于每个点最多被访问一次,BFS 的时间复杂度为 O(m * n),其中 m 是迷宫的行数,n 是列数。
    • 空间复杂度:BFS 使用了一个 queue 和一个 visited 数组,因此空间复杂度同样是 O(m * n)

6. 示例分析

我们以几个具体的示例来展示代码的执行过程。

示例 1:
maze = [["+","+",".","+"],[".",".",".","+"],["+","+","+","."]]
entrance = [1,2]

在这里插入图片描述

  • 入口坐标是 (1,2)
  • 第一次从 (1,2) 开始,向左移动到 (1,1),向上移动到 (0,2),而 (0,2) 是一个边界点,符合出口条件。
  • 返回步数 1
示例 2:
maze = [["+","+","+"],[".",".","."],["+","+","+"]]
entrance = [1,0]

在这里插入图片描述

  • 入口坐标是 (1,0)
  • 第一次从 (1,0) 开始,向右移动到 (1,1)
  • 第二次向右移动到 (1,2),并且 (1,2) 是边界点,返回步数 2
示例 3:
maze = [[".","+"]]
entrance = [0,0]

在这里插入图片描述

  • 迷宫只有一个空格,且入口本身就是边界,没有其他出口。
  • 因此,返回 -1

7. BFS 模板总结

BFS 是解决 最短路径问题 的常用算法。常见的 BFS 模板如下:

// 初始化队列和访问数组
queue<pair<int, int>> q;
vector<vector<bool>> visited(m, vector<bool>(n, false));// 将起点加入队列并标记为访问过
q.push({startX, startY});
visited[startX][startY] = true;// BFS 主循环
while (!q.empty()) {int size = q.size(); // 获取当前层的节点数量// 遍历当前层的每个节点for (int i = 0; i < size; ++i) {auto [x, y] = q.front();q.pop();// 执行某些操作// 向四个方向扩展for (auto [dx, dy] : directions) {int newX = x + dx;int newY = y + dy;// 检查是否可以移动到新的点并继续 BFSif (/* 满足条件 */) {q.push({newX, newY});visited[newX][newY] = true;}}}
}

8. 总结

通过这篇文章,我们详细讨论了如何通过 广度优先搜索(BFS) 解决迷宫问题。我们展示了完整的 C++ 实现代码,逐步分析了 BFS 的原理,并总结了常见的 BFS 模板。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1552919.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

超声波扫描显微镜SAM有什么作用?

知识星球里的学员问&#xff1a;在晶圆厂中很少见到超声波扫描显微镜&#xff0c;但是在封测厂中会经常用到&#xff0c;麻烦讲一下超声波扫描显微镜的原理与用途 什么是超声波扫描显微镜&#xff1f; 超声波扫描显微镜&#xff0c;英文名scanning acoustic microscope&#…

【论文阅读】Equivariant Multi-Modality Image Fusion(CVPR2024)

Equivariant Multi-Modality Image Fusion&#xff08;CVPR2024&#xff09; 现有方法存在的问题 由于现实中没有一种传感器可以同时捕捉所有模态的信息&#xff0c;因此缺乏真实的融合图像作为训练的参照标准&#xff0c;这对深度学习模型的训练带来了挑战。 基于生成对抗网…

2024 全新体验:国学心理 API 接口来袭

在当今快节奏的生活中&#xff0c;人们对于心理健康越来越重视。而研究发现&#xff0c;国学心理学乃至传统文化中的思想智慧&#xff0c;对于人们的心理健康有着独特且深远的影响。为了让更多人能够体验到国学心理的魅力&#xff0c;2024年全新推出的国学心理 API 接口&#x…

基于单片机的两轮直立平衡车的设计

本设计基于单片机设计的两轮自平衡小车&#xff0c;其中机械部分包括车体、车轮、直流电机、锂电池等部件。控制电路板采用STC12C5A60S2作为主控制器&#xff0c;采用6轴姿态传感器MPU6050测量小车倾角&#xff0c;采用TB6612FNG芯片驱动电机。通过模块化编程完成了平衡车系统软…

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类 变电站红外检测数据集 名称 变电站红外检测数据集 (Substation Infrared Detection Dataset) 规模 图像数量&#xff1a;1185张图像。类别&#xff1a;13种设备类型。标注个数&#xff1a;2813个标注。 数据划分…

关于TF-IDF的一个介绍

在这篇文章中我将介绍TF-IDF有关的一些知识&#xff0c;包括其概念、应用场景、局限性以及相应的代码。 一、概念 TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff09;是一种广泛用于信息检索和文本挖掘中的统计方法&#xff0c;用于评估一个词在一个文…

鸿蒙ArkUI实战开发-主打自研语言及框架

ArkUI 是 HarmonyOS 的声明式 UI 开发框架&#xff0c;而 ArkUI-X 是基于 ArkUI 框架扩展而来的跨平台开发框架。ArkUI-X 支持 HarmonyOS、OpenHarmony、Android 和 iOS 平台&#xff0c;允许开发者使用一套代码构建支持多平台的应用程序。 一、ArkUI-X 的实战开发步骤 在实战开…

存储主动防御,为什么Gartner技术曲线尤为重视?

【科技明说 &#xff5c; 科技热点关注】 近来&#xff0c;从Gartner发布的2024年存储技术成熟曲线&#xff08;Hype Cycle for Storage Technologies ,2024&#xff09;的相关报告看出&#xff0c;到2028年&#xff0c;所有存储产品都将融入专注于数据主动防御的网络存储功能&…

西电25考研 VS 24考研专业课大纲变动汇总

01专业课变动 西安电子科技大学专业课学长看到953网络安全基础综合变为 893网络安全基础综合&#xff0c;这是因为工科要求都必须是8开头的专业课&#xff0c;里面参考课本还是没变的&#xff0c;无非就是变了一个名字 对于其他变动专业课也是同理的 02专业课考纲内容变化 对于…

深度学习笔记18_TensorFlow实现猫狗识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 一、我的环境 1.语言环境&#xff1a;Python 3.9 2.编译器&#xff1a;Pycharm 3.深度学习环境&#xff1a;TensorFlow 2.10.0 二、GPU设置…

【拥抱AIGC】通义灵码策略配置

通义灵码企业级策配置支持智能问答、行间代码生成安全过滤器相关策略配置。 适用版本 企业标准版、企业专属版 通义灵码管理员、组织内全局管理员&#xff08;专属版&#xff09;在通义灵码控制台的策略配置中进行安全过滤器的配置&#xff0c;开启后&#xff0c;企业内开发…

SOMEIP_ETS_146: SD_ResetInterface

测试目的&#xff1a; 验证DUT在重置后&#xff0c;TestFieldUINT8的值是否至少与重置前设置的值不同&#xff0c;符合SOME/IP规范。 描述 本测试用例旨在确保DUT的ETS能够正确响应重置请求&#xff0c;并且在重置后&#xff0c;特定的测试字段&#xff08;TestFieldUINT8&a…

数据仓库的建设——从数据到知识的桥梁

数据仓库的建设——从数据到知识的桥梁 前言数据仓库的建设 前言 企业每天都在产生海量的数据&#xff0c;这些数据就像无数散落的珍珠&#xff0c;看似杂乱无章&#xff0c;但每一颗都蕴含着潜在的价值。而数据仓库&#xff0c;就是那根将珍珠串起来的线&#xff0c;它能够把…

仅需10G显存,使用 Unsloth 微调 Qwen2 并使用 Ollama 推理

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、算法项目落地经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接如…

YOLOv11改进 | 注意力篇 | YOLOv11引入ACmix注意力机制

1. ACmix介绍 1.1 摘要&#xff1a;卷积和自注意力是表示学习的两种强大技术&#xff0c;它们通常被认为是两种彼此不同的同行方法。 在本文中&#xff0c;我们表明它们之间存在很强的潜在关系&#xff0c;从某种意义上说&#xff0c;这两种范式的大量计算实际上是通过相同的操…

Linux 进程状态、僵尸进程与孤儿进程

目录 0.前言 1. 进程状态 1.1 定义 1.2 常见进程 2.僵尸进程 2.1 定义 2.2 示例 2.3 僵尸进程的危害与防止方法 3. 孤儿进程 3.1 介绍 3.2 示例 4.小结 &#xff08;图像由AI生成&#xff09; 0.前言 在上一篇文章中&#xff0c;我们介绍了进程的基本概念、进程控制块&#…

蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)

一、什么是IIC&#xff1f;24C02存储器有什么用&#xff1f; IIC &#xff08;IIC 是半双工通信总线。半双工意味着数据在某一时刻只能沿一个方向传输&#xff0c;即发送数据的时候不能接收数据&#xff0c;接收数据的时候不能发送数据&#xff09;即集成电路总线&#xff08;…

Activiti7 工作流引擎学习

目录 一. 什么是 Activiti 工作流引擎 二. Activiti 流程创建步骤 三. Activiti 数据库表含义 四. BPMN 建模语言 五. Activiti 使用步骤 六. 流程定义与流程实例 一. 什么是 Activiti 工作流引擎 Activiti 是一个开源的工作流引擎&#xff0c;用于业务流程管理&#xf…

第二弹:面向对象编程中的类与对象

文章目录 面向对象编程中的类与对象1. 类与对象的定义1.1 类和对象的概念1.2 类的基本定义 2. 类的封装2.1 类的封装语法2.2 类成员访问权限2.3 struct和class的区别2.4 类封装与成员函数定义分离 3. 类对象的创建与销毁3.1 静态与动态对象的创建3.2 对象的销毁 4. 构造函数和析…

深入解析 ConcurrentHashMap:从 JDK 1.7 到 JDK 1.8

✨探索Java基础 ConcurrentHashMap✨ 引言 ConcurrentHashMap 是 Java 中一个线程安全的高效 Map 集合。它在多线程环境下提供了高性能的数据访问和修改能力。本文将详细探讨 ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 中的不同实现方式&#xff0c;以及它们各自的优缺点。 …