BFS与最短路径

BFS

基本步骤

要实现图的广度优先遍历,需要借助队列这一结构。

  1. 将入口顶点入队,同时标记为已访问
  2. 若队列不为空,则从队列中取出一个顶点访问
  3. 检查与该顶点相连的其它顶点,若没有被访问过则入队,同时标记为已访问
  4. 重复2、3步骤

示例代码

下面举一个例子:

#include <iostream>
#include <vector>
#include <queue>

std::vector<std::vector<int>> g_Graph;

static void Input()
{
    int vertexNums, edgeNums;
    std::cin >> vertexNums >> edgeNums;

    g_Graph.resize(vertexNums + 1, std::vector<int>(vertexNums + 1));
    int from, to, weight;
    for (size_t i = 0; i < edgeNums; i++)
    {
        std::cin >> from >> to >> weight;
        g_Graph[from][to] = weight;
        g_Graph[to][from] = weight;
    }
}

static void BFS()
{
    std::vector<bool> visited(g_Graph.size(), false);
    std::queue<int> queue;

    queue.push(1);
    visited[1] = true;

    int vertex;
    while (!queue.empty())
    {
        vertex = queue.front();
        queue.pop();

        std::cout << vertex << ' ';

        for (size_t i = 1; i < g_Graph.size(); i++)
        {
            if (!visited[i] && g_Graph[vertex][i] != 0)
            {
                queue.push(i);
                visited[i] = true;
            }
        }
    }

    std::cout << std::endl;
}

int main()
{
    Input();
    BFS();

    return 0;
}

读者可以用这个代码自行测试。

BFS与无权图最短路径查找

BFS可以用于查找无权图的最短路径。BFS是层层递进进行遍历的,第一次访问某一个顶点的时候,此时经过的路径就是从起始顶点到该顶点的最短路径。

下面是示例代码:

static std::vector<std::vector<int>> g_Graph;

static void BFSGetShortestPath(int start, int target)
{
    std::vector<bool> visited(g_Graph.size(), false);
    std::queue<int> queue;
    std::vector<int> parent(g_Graph.size(), -1); // 用于回溯路径,下标为顶点,元素为其上一个顶点

    queue.push(start);
    visited[start] = true;
    int vertex;
    while (!queue.empty())
    {
        vertex = queue.front();
        queue.pop();

        if (vertex == target) // 如果当前访问的顶点是目标顶点
        {
            std::vector<int> path;
            int cursor = target;
            while (cursor != -1) // 通过parent获得路径
            {
                path.push_back(cursor);
                cursor = parent[cursor];
            }

            std::reverse(path.begin(), path.end()); // 反转之后得到正确的路径
            for (auto& a : path)
                std::cout << a << ' ';
            std::cout << std::endl;
            return;
        }

        for (size_t i = 1; i < g_Graph.size(); i++) // 正常的BFS遍历操作
        {
            if (visited[i] == false && g_Graph[vertex][i] != 0) // 遍历vertex的邻接顶点
            {
                queue.push(i);
                visited[i] = true;
                parent[i] = vertex;
            }
        }
    }
}
<think>首先,用户的问题是关于在408考研中使用BFS算法求解最短路径问题的方法和例题解析。用户提到了BFS算法,并引用了几个相关的引用内容。 回顾系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 用户提供的引用: - [^1]: 比较了BFS、Dijkstra和Floyd算法,指出BFS适用于无权图。 - [^2]: 提到Bellman-Ford和SPFA算法,但408考研不要求。 - [^3]: 讨论了DFS和BFSBFS适用于最短路径问题。 - [^4]: 解释了Floyd算法的迭代过程。 用户的具体需求:使用BFS算法解决最短路径问题,并应用于408考研相关题目。用户想要方法和例题解析。 关键点: - BFS算法适用于无权图的最短路径问题。 - 在考研中,BFS常用于图的遍历和最短路径计算。 - 我需要提供清晰的方法步骤和例题解析。 结构化回答: 1. **介绍BFS算法**:简要解释BFS的基本原理,特别是用于最短路径。 2. **方法步骤**:详细描述如何使用BFS求解最短路径的步骤。 3. **例题解析**:提供一个408考研风格的例题,并逐步解析。 4. **注意事项**:提醒BFS的适用条件(无权图)。 5. **生成相关问题**:根据内容,生成2-3个相关问题。 确保使用中文,并正确应用引用。引用[^1]和[^3]特别相关,因为它们提到了BFS用于最短路径。 回答大纲: - **引言**:简述BFS最短路径中的应用。 - **BFS求解最短路径的方法**: - 步骤1:初始化队列和距离数组。 - 步骤2:从起点开始BFS遍历。 - 步骤3:更新距离并记录路径。 - **例题解析**: - 选择一个简单的无权图例题。 - 逐步展示BFS过程。 - **总结**:强调BFS的适用性和限制。 - **相关问题**:生成2-3个相关问题。 例题选择:找一个经典的408考研题或类似问题。例如,一个无权图,求从指定起点到终点的最短路径。 引用应用: - 在提到BFS适用于无权图时,引用[^1]。 - 在讨论BFS用于最短路径时,引用[^3]。 数学表达式:如果有距离计算,使用$...$格式。例如,距离$d[v]$。 最后,生成相关问题: 1. 如何优化BFS用于带权图? 2. BFS和DFS在最短路径问题中的区别? 3. 在408考研中,BFS算法的常见考点是什么?</think>### BFS算法求解最短路径问题的方法例题解析(408考研适用) 在408考研中,广度优先搜索(BFS算法是求解**无权图最短路径问题**的核心方法。BFS通过逐层遍历图,确保首次访问节点时即找到从起点到该节点的最短路径(路径长度以边数计算)[^3]。本回答将逐步解析方法例题,确保内容符合考研要求。 #### 一、BFS求解最短路径的基本原理 BFS基于队列实现,从起点开始逐层扩展,确保每个节点首次被访问时,路径长度最小。其核心思想是: - **无权图假设**:BFS仅适用于边权值均为1的无权图(或等权图)。若图带权,需使用Dijkstra等算法[^1]。 - **时间复杂度**:$O(|V| + |E|)$,其中$|V|$为顶点数,$|E|$为边数,适合图规模适中的场景。 - **关键数据结构**: - 队列(Queue):存储待访问节点。 - 距离数组(dist):记录起点到各节点的最短距离,初始化为$-1$(未访问)或$\infty$。 - 前驱数组(prev):记录路径(可选)。 #### 二、BFS求解最短路径的步骤 以下步骤以伪代码形式描述,适用于无向图或有向图(需调整邻接关系): 1. **初始化**: - 创建队列$Q$,将起点$s$入队。 - 初始化距离数组$dist$:$dist[s] = 0$,其他节点$dist[v] = -1$(表示未访问)。 - (可选)初始化前驱数组$prev$:$prev[v] = \text{null}$。 2. **BFS遍历**: - 当$Q$非空时: - 出队节点$u$。 - 遍历$u$的所有邻接节点$v$: - 如果$dist[v] = -1$(未访问): - $dist[v] = dist[u] + 1$(更新距离)。 - $prev[v] = u$(记录路径)。 - 将$v$入队。 3. **输出结果**: - $dist[v]$即为起点$s$到$v$的最短路径长度。 - 通过$prev$数组回溯路径(例如,从终点$t$回溯到$s$)。 **注意事项**: - BFS保证最短路径的正确性,因为其按层遍历,首次访问时路径最短。 - 若图不连通,部分节点$dist[v]$保持$-1$,表示不可达[^3]。 - 在408考研中,BFS常用于邻接矩阵或邻接表存储的图(考题常考邻接矩阵)。 #### 三、例题解析(408考研风格) **例题**:给定无向图$G$(无权),顶点集$V = \{A, B, C, D, E\}$,边集$E = \{(A,B), (A,C), (B,D), (C,D), (D,E)\}$。求从起点$A$到终点$E$的最短路径长度及路径。 **解题步骤**: 1. **图表示**:使用邻接表存储(考研常见形式): - $A: [B, C]$ - $B: [A, D]$ - $C: [A, D]$ - $D: [B, C, E]$ - $E: [D]$ 2. **BFS过程**(逐步模拟): - 初始化:$dist[A] = 0$,其他$dist = -1$;队列$Q = [A]$。 - 步骤1:出队$A$,访问邻接点$B, C$。 - $dist[B] = dist[A] + 1 = 1$,$prev[B] = A$;$B$入队。 - $dist[C] = dist[A] + 1 = 1$,$prev[C] = A$;$C$入队。 - $Q = [B, C]$。 - 步骤2:出队$B$,访问邻接点$D$($A$已访问,跳过)。 - $dist[D] = dist[B] + 1 = 2$,$prev[D] = B$;$D$入队。 - $Q = [C, D]$。 - 步骤3:出队$C$,访问邻接点$D$($D$已访问,跳过)。 - $Q = [D]$。 - 步骤4:出队$D$,访问邻接点$E$。 - $dist[E] = dist[D] + 1 = 3$,$prev[E] = D$;$E$入队。 - 终点$E$已访问,停止遍历。 3. **结果输出**: - 最短路径长度:$dist[E] = 3$。 - 路径回溯:$E \to D \to B \to A$(即$A \to B \to D \to E$)。 - **验证**:路径$A \to B \to D \to E$长度为3,其他路径(如$A \to C \to D \to E$)长度也为3,但BFS首次访问时即得最短解。 **解析关键**: - 本题为无权图,BFS可直接应用,时间复杂度$O(5+5)=O(1)$(小图示例)[^1]。 - 在考研中,类似题常要求写出$dist$数组或路径序列,例如2020年真题曾考察BFS遍历序列。 #### 四、总结考研应用要点 - **适用场景**:BFS专解无权图最短路径,是408高频考点(如图的遍历、连通性判断)[^3]。 - **常见错误**: - 混淆带权图:若边权不等,BFS结果错误,需用Dijkstra[^1]。 - 忽略图存储方式:邻接矩阵需注意空间复杂度$O(|V|^2)$。 - **扩展**:BFS也可用于树或网格图(如迷宫问题),但考研重点在图结构。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值