【算法 02】一题学习BFS和DFS算法

news2024/11/24 13:37:34

一题学习BFS和DFS算法


请添加图片描述

洛谷题目解析:【深基18.例3】查找文献

题目背景

小K热衷于在洛谷博客上阅读文章并探索其中的知识。每篇文章都可能包含指向其他博客文章的参考文献链接。小K的求知欲非常强,如果他阅读了某篇文章,他一定会去查看这篇文章的所有参考文献(但前提是这些参考文献他之前还没看过)。现在,我们帮助小K设计一种方法,确保他能不重复、不遗漏地阅读完所有他能看到的文章。

题目描述

洛谷博客共有n(n≤105)篇文章(编号为1到n)和m(m≤106)条参考文献引用关系。小K已经打开了编号为1的文章。我们需要通过深度优先搜索(DFS)和广度优先搜索(BFS)两种方式,来模拟小K阅读文章的过程,并输出遍历的结果。

输入输出格式

输入格式

  • 第一行包含两个整数nm,分别表示文章总数和参考文献关系数。
  • 接下来m行,每行包含两个整数X,Y,表示文章X有参考文献Y

输出格式

  • 第一行输出DFS遍历的结果。
  • 第二行输出BFS遍历的结果。

样例

样例输入

8 9  
1 2  
1 3  
1 4  
2 5  
2 6  
3 7  
4 7  
4 8  
7 8

样例输出

1 2 5 6 3 7 8 4  
1 2 3 4 5 6 7 8

解题思路

深度优先搜索(DFS)

DFS是一种用于遍历或搜索树或图的算法。它从根节点开始,尽可能深地搜索树的分支,直到达到叶子节点,然后回溯到前一个节点,继续探索尚未探索的分支。在DFS中,我们使用递归来实现这一过程。

广度优先搜索(BFS)

BFS也是一种遍历或搜索图或树的算法。它从根节点开始,首先访问根节点的所有相邻节点,然后对每个相邻节点,再访问它们的所有未被访问的相邻节点,以此类推,直到所有节点都被访问。在BFS中,我们通常使用队列来实现这一过程。

代码实现

以下是C++的实现代码,包含了DFS和BFS的具体实现:

#include<iostream>  
#include<vector>  
#include<queue>  
#include<algorithm>  
using namespace std;  
  
const int MAXN = 100010;  
vector<int> graph[MAXN];  
bool visitedDFS[MAXN], visitedBFS[MAXN];  
  
// DFS实现  
void dfs(int node) {  
    if (visitedDFS[node]) return;  
    visitedDFS[node] = true;  
    cout << node << " ";  
    for (int neighbor : graph[node]) {  
        dfs(neighbor);  
    }  
}  
  
// BFS实现  
void bfs(int start) {  
    queue<int> q;  
    q.push(start);  
    visitedBFS[start] = true;  
    while (!q.empty()) {  
        int current = q.front();  
        q.pop();  
        cout << current << " ";  
        for (int neighbor : graph[current]) {  
            if (!visitedBFS[neighbor]) {  
                q.push(neighbor);  
                visitedBFS[neighbor] = true;  
            }  
        }  
    }  
}  
  
int main() {  
    int n, m;  
    cin >> n >> m;  
    for (int i = 0; i < m; i++) {  
        int from, to;  
        cin >> from >> to;  
        graph[from].push_back(to);  
    }  
    // 由于题目要求先访问编号较小的文章,我们不需要对邻接表排序  
    dfs(1);  
    cout << endl;  
    fill(visitedBFS, visitedBFS + MAXN, false); // 清除BFS的访问标记  
    bfs(1);  
    return 0;  
}

当然,以下是这段代码中算法部分的详细讲解:

1. 图的表示

代码使用了一个邻接表(vector<int> g[MAX];)来表示图。g[i] 是一个存储了所有与节点 i 相邻的节点编号的 vector。这种表示法适用于稀疏图,因为它只存储实际存在的边,而不是为每对可能的节点都保留一个空间(如邻接矩阵)。

2. 深度优先搜索(DFS)

dfs 函数实现了深度优先搜索算法。它从给定的起始节点 u 开始,递归地探索图:

  • 首先检查节点 u 是否已经被访问过(通过 used[u] 数组)。如果是,则直接返回,避免重复访问。
  • 将节点 u 标记为已访问(used[u] = 1;)。
  • 输出节点 u 的编号。
  • 然后,对于节点 u 的每一个邻接节点 e,递归调用 dfs(e)

3. 广度优先搜索(BFS)

bfs 函数实现了广度优先搜索算法。它从给定的起始节点 u 开始,逐层遍历图:

  • 使用一个队列 q 来存储待访问的节点。首先将起始节点 u 加入队列。
  • 当队列不为空时,循环执行以下操作:
    • 从队列中取出一个节点 uq.front()),然后将其从队列中移除(q.pop())。
    • 检查节点 u 是否已经被访问过(通过 used2[u] 数组)。如果是,则跳过当前循环的剩余部分,继续处理下一个节点。
    • 输出节点 u 的编号。
    • 将节点 u 标记为已访问(used2[u] = 1;)。
    • 对于节点 u 的每一个邻接节点 e,将其加入队列 q 中以便后续访问。

4. 输入与输出

  • 输入部分首先读取两个整数 ab,其中 a 表示图中节点的数量(尽管 g 数组的大小已经通过 MAX 定义为 100010,但 a 可能用于后续验证或处理),b 表示边的数量。
  • 然后,读入 b 条边,每条边由两个整数 cd 表示,意味着存在一条从节点 c 到节点 d 的边。这些边被添加到邻接表中。
  • 在遍历所有边之后,对每个节点的邻接节点进行排序(这可能是为了某种特定的输出顺序或后续处理的需要)。
  • 最后,从节点 1 开始分别执行 DFS 和 BFS,并输出访问节点的顺序。DFS 的输出将展示从节点 1 开始的一条深度优先遍历路径,而 BFS 的输出将展示从节点 1 开始逐层向外扩展的广度优先遍历路径。

5. 注意事项

  • usedused2 数组分别用于 DFS 和 BFS 的访问标记,以避免重复访问节点。

  • 在实际应用中,如果图是有向的,则这种表示和遍历方法是有效的。如果图是无向的,那么可能需要在添加边时同时添加两个方向的边(即 g[c].push_back(d);g[d].push_back(c);)。

  • 排序邻接节点可能是为了特定的输出要求或算法优化,但在某些情况下可能不是必需的。

  • 题目中提到“不保证编号为1的文章没有被其他文章引用”,但在这个问题中,我们是从编号为1的文章开始遍历,所以这一点不影响我们的遍历过程。

  • 在DFS中,我们使用了递归函数来深入探索每一个分支。当遇到已经访问过的节点时,我们会直接返回,避免重复遍历。

  • 在BFS中,我们使用了队列来存储待访问的节点。每次从队列中取出一个节点进行访问,并将其所有未访问的邻接节点加入队列中。这样可以保证我们总是先访问离起始节点最近的节点。

  • 注意,在每次使用完DFS或BFS后,我们都需要重置访问标记数组,以便下一次遍历能够正确进行。但在本题中,由于我们只进行了一次DFS和一次BFS,所以只需在BFS前重置BFS的访问标记数组即可。

  • 最后,由于题目要求输出编号较小的文章在前,而我们在读入边时,默认将每个节点的邻接节点按照输入顺序存储在了邻接表中。由于C++的vector在遍历时会按照元素被添加的顺序进行,所以自然满足了这个要求,我们无需对邻接表进行额外的排序操作。

    总结

    通过这道题,我们复习了图的深度优先搜索(DFS)和广度优先搜索(BFS)两种遍历算法,并了解了它们在实际问题中的应用。同时,我们也学会了如何使用邻接表来表示图,并如何通过递归和队列来实现DFS和BFS的遍历过程。希望这次解析能够帮助大家更好地理解和掌握这两种重要的图遍历算法。

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

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

相关文章

分享一个基于微信小程序的智慧校园服务平台(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

LLM可解释性的未来希望?稀疏自编码器是如何工作的,这里有一份直观说明

点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 简而言之&#xff1a;矩阵 → ReLU 激活 → 矩阵 在解释机器学习模型方面&#xff0c;稀疏自编码器&#xff08;SAE&#xff09;是一种越来越常用的工具&#xff08;虽然 SAE 在 1997 年左右就已经问世了&am…

keil工程一下子跳出来非常多错误的原因可能

1.没有选择c99编译模式 2.没有选择优化模式为编码时合适的模式 3.start文件有问题 4.路径没有引用

用模方软件做单体化建模,修图时需要用哪种软件?可以用Photoshop吗

联动单体可以用草图大师、3Dmax&#xff1b;修纹理可以联动使用Photoshop。 模方是一款针对实景三维模型的冗余碎片、水面残缺、道路不平、标牌破损、纹理拉伸模糊等共性问题研发的实景三维模型修复编辑软件。模方4.1新增自动单体化建模功能&#xff0c;支持一键自动提取房屋结…

一芯解锁「看家」新体验,航芯高性价比猫眼智能锁方案,让安全看得见!

随着智能门锁市场规模逐年递增&#xff0c;行业“内卷”也持续激烈。伴随着一路加码的功能卖点&#xff0c;智能门锁制造商正面临着产品功能芯片增多和成本优化的双重挑战。消费者不仅追求易用性、智能化和美观性&#xff0c;更期待产品具有良好的性价比。 而在智能门锁的众多…

ICML 2024 论文解析:解读量化感知的 Transformer 模型密态推理

导语&#xff1a;ICML 国际机器学习大会&#xff08;International Conference on Machine Learning&#xff0c;简称 ICML&#xff09;是机器学习领域最重要和最有影响力的学术会议之一。《Ditto: Quantization-aware Secure Inference of Transformers upon MPC&#xff08;量…

【中项】系统集成项目管理工程师-第10章 项目整合管理-10.2制订项目管理计划

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

【YashanDB数据库】大事务回滚导致其他操作无法执行,报错YAS-02016 no free undo blocks

问题现象 客户将一个100G的表的数据插入到另一个表中&#xff0c;使用insert into select插入数据。从第一天下午2点开始执行&#xff0c;到第二天上午10点&#xff0c;一直未执行完毕。 由于需要实施下一步操作&#xff0c;客户kill重启了数据库&#xff0c;之后数据库一直回…

《清远折叠》,数智广东第一个SPN政务专网故事

今天&#xff0c;越来越多物理世界中的产业&#xff0c;正在与数字世界完成交汇&#xff0c;改变着我们习以为常的生活方式。 比如政务专网&#xff0c;就通过一张专用网络&#xff0c;将物理世界的政府部门与城市居民&#xff0c;在数字世界中“折叠”到一起&#xff0c;让人们…

Weblogic 漏洞

1.弱口令 访问默认用户名&#xff1a;weblogic 密码&#xff1a; Oracle123 点击安装 点击上载文件 将jsp木马打包&#xff0c;改为war,上传&#xff0c;一直下一步&#xff0c;最后点完成&#xff0c;访问99/99.jsp 使用工具连接 2.CVE-2017-3506 使用工具检测&#xff0c…

static的注意事项

总结 /*** ClassName Student* author gyf* Date 2024/8/5 23:48* Version V1.0* Description : */ public class Student {String name;int age;static String tecname;// 这个this 是虚拟机默认的public void show(Student this){System.out.println(this);System.out.prin…

ASP.NET Core 基础 - Razor Pages Web 应用

目录 一. 创建项目 二. 检查项目文件 三. 添加模型 四. 添加数据 五. 基架 六. 使用数据库 七. 总结 一. 创建项目 新建项目 点击运行 二. 检查项目文件 Pages 文件夹 包含 Razor 页面和支持文件。 每个 Razor 页面都是一对文件&#xff1a; 一个 .cshtml 文件&#xf…

如何白手起家?

作者:明王 日期:2016-07-1121:19 白手起家第一步&#xff0c;不是开公司&#xff0c;是脱离原生家庭&#xff0c;白手起家第二步&#xff0c;不是开公司&#xff0c;是挑个上升行业。白手起家第三步&#xff0c;不是开公司&#xff0c;是攒启动资金&#xff0c;白手起家笔四步&…

php反序列靶场serial

1.安装环境 2.使用kali扫描nat端口 3.使用物理机首先访问80端口&#xff0c;提示这里是新cookie进行程序测试&#xff0c;那我们查看cookie 4.f12查看&#xff0c;是一段base64编码 5.进行目录扫描 6.进入backup子目录发现有压缩包 7.下载bak.zip里面有三个源代码&#xff0…

单机部署ELK + Filebeat 收集应用日志

目录 前言一、ELK是什么&#xff1f;二、系统环境&#xff08;CentOS 7&#xff09;&#xff08;2C4G的机器。。。&#xff09;三、安装步骤3.1 安装ElasticSearch3.1.1 解压到/usr/local3.1.2 修改jvm堆配置&#xff08;可选&#xff0c;测试服务器内存低&#xff09;3.1.3 修…

C++初阶:类和对象(下)

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 1.再探构造函数 1.1构造函数体内赋值 之前…

Parsing error: The keyword ‘interface‘ is reserved配置优化

当我们在创建Vue项目时,Vue默认是配置了eslint代码规范检查的,不过我们在项目中Typescript来编写代码时,却报了标题的错误,对应的代码如下: <script lang="ts"> export default{name: "DlHeader" } </script><script setup lang=&quo…

利用OpenCvSharp进行图像相关操作

前言 程序设计过程&#xff0c;有时也需要对图像进行一些简单操作&#xff0c;C#没有现成的图像处理库&#xff0c;但有人对OpenCV进行了包装&#xff0c;我们可以很方便的使用OpenCvSharp对图像进行操作。当然了&#xff0c;这也需要使用的人员进行一些研究&#xff0c;但相对…

【C语言篇】猜数字游戏(赋源码)

文章目录 猜数字游戏前言随机数生成randsrandtime设置随机数生成范围 猜数字游戏的实现 猜数字游戏 前言 在前两篇博客对于分支和循环语句进行了详细的介绍&#xff1a; 分支语句详解 循环语句详解 我们就可以写一写稍微有趣的代码了&#xff0c;比如&#xff1a; 写一个…

用uniapp 及socket.io做一个简单聊天app 撤回聊天及保留聊天记录 6

撤回的设计 通过聊天&#xff0c;发送一个信息&#xff0c;界面自动将信息撤回&#xff0c; 当时要有时间的限制。同时也要将撤回记录到数据库中。async sendMessage(message, type text) {this.$refs.popup.close();const messageData {sn: uuidv4(),group_name: this.gro…