【图论】图的深度优先遍历与广度优先遍历(图文讲解)
一、前言
看懂这篇博客你需要提前知道这些知识点
1.C++链式前向星存图;
2.dfs和bfs是什么以及基本概念;
3.C++STL中的queue,队列数据结构的简单知识点;
4.有关图的一些简单的概念;
图论是一个很重要的知识块,在学习如何遍历图之前,我们首先当然得知道要怎样去建图。在下面的内容里,我们将使用链式前向星来建图,如果对建图有什么问题的话可以移步这篇博客来学习。
链式前向星
在了解建图的方法后,我们当然要开始考虑如何遍历图中的每一个点,在这里,我们将使用两种最基础的遍历方式-----深度优先搜索(DFS)与广度优先搜索(BFS)
首先,我们假设已经把一个有向图建好了,其实无向图就是特殊的有向图,就不单独说明了。
二、深度优先搜索遍历(DFS)
概念: 如果在之前已经学习了深度优先搜索的话其实就不用多解释可以直接看例题和代码了,但在这里还是要简单讲解一下。所谓DFS,就是从起点开始,找准一个方向直到走不了为止,然后再原路返回,再找到一个能走的地方继续走的思路。如图
点的遍历顺序为:1,2,4,7,8,5,3,6;
这就是深度优先搜索的思路与在树中的实现。
例题与代码实现:Acwing 树的重心
给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。输入格式
第一行包含整数 n,表示树的结点数。接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。输出格式
输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。数据范围
1≤n≤1e5
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
其实这道题对于刚刚学图论的人而言好像有一点难了,因为这一题不但考到了图的遍历,还需要知道树形dp的处理与状态的计算,如果这道题能懂,那么就表示完全搞定了dfs遍历图的知识点了。先附上ac代码吧,代码里会有解释。
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7;int n;
int ne[N], h[N], e[N], id = 1; //链式前向星
bool ch[N];
int ans=INF;
void add(int a, int b)
{e[id] = b;ne[id] = h[a];h[a] = id++;
}int dfs(int x) //x是根节点的编号
{ch[x] = true; //标记这个点被遍历过了,避免死循环int sum = 1; //以x为根的树的节点数量int res = 0; //所有子树最长的子树的长度int te = 0;for (int i = h[x]; i != -1; i = ne[i]){int j = e[i];if (!ch[j]){//这里的递归实现是dfs实现的精髓te=dfs(j), sum +=te ;res = max(res, te);}}res = max(res, n - sum);ans = min(ans, res);return sum;
}void solve()
{mem(h, -1); //h数组的初始化cin >> n;for (int i = 1; i <= n - 1; i++){int x, y;cin >> x >> y;//无向图的边就是两条有向边add(x, y);add(y, x);}dfs(1);cout << ans << endl;
}int main()
{std::ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);solve();return 0;
}
三、广度优先搜索遍历(BFS)
概念: BFS广度优先搜索,与DFS不同,BFS在搜索到一个点后,会先搜索他周围的与它相连所有点,然后再搜索所有有与它相连的的点的相连的的点。这么说是不是很绕?让我们看图理解一下吧。
遍历顺序:1,2,3,4,5,6,7,8;
队列q的元素情况为
1.{1};
2.{2,3};
3.{4,5,6};
4.{7,8};
看不懂上面4行的意思就去看看bfs入门博客以及数据结构:队列的知识点。
例题与代码实现: Acwing 图中点的层次
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环。所有边的长度都是 1,点的编号为 1∼n。请你求出 1 号点到 n 号点的最短距离,如果从 1 号点无法走到 n 号点,输出 −1。输入格式
第一行包含两个整数 n 和 m。接下来 m 行,每行包含两个整数 a 和 b,表示存在一条从 a 走到 b 的长度为 1 的边。输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。数据范围
1≤n,m≤1e5
这题就是纯BFS遍历图的题了,应该要简单一些。想搞懂bfs遍历就必须要看懂这道题。我们从起点开始遍历,如果我们发现终点被放进队列中了,就停止BFS,否则就清空队列,把子节点放进队列。
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7;int n, m;
int h[N], e[N], ne[N], id = 1;
bool ch[N];
void add(int a, int b)
{e[id] = b, ne[id] = h[a], h[a] = id++;
}int ans = 0; //这是答案
void bfs(int u) //u是起点
{ch[u] = 1; //防止死循环queue<int>q; //主队列q.push(u); //把起点放进去while (!q.empty()){queue<int>t; //临时队列while (!q.empty()) //清空主队列,把数据全部放进临时队列中{if (q.front() == n)return; //终点被放进去了就结束bfs函数t.push(q.front());q.pop();}while (!t.empty()) //把当前所有点的子节点放进主队列中去{int te = t.front(); //拿出队首for (int i = h[te]; i != -1; i = ne[i]) //找出所有子节点{if (ch[e[i]]) //防止死循环continue;else{ch[e[i]] = 1;q.push(e[i]);}}t.pop();}ans++; //每bfs一层,路径长度加一}ans = -1; //遍历了整张图都每找到中点,就返回-1;
}void solve()
{mem(h, -1);cin >> n >> m;for (int i = 0; i < m; i++){int a, b;cin >> a >> b;add(a, b);}bfs(1);cout << ans << endl;
}int main()
{//std::ios::sync_with_stdio(false);//cin.tie(0), cout.tie(0);solve();return 0;
}
作者:Avalon Demerzel,喜欢我的博客就点个赞吧,更多图论与数据结构知识点请见作者专栏《图论与数据结构》
【图论】图的深度优先遍历与广度优先遍历(图文讲解)相关推荐
- 广度优先搜索生成树怎么画_图的深度优先遍历与广度优先遍历以及最小生成树...
图的深度优先遍历 题目:写出附从每个顶点出发的一次深度优先搜索遍历序列.在纸上画出遍历过程和序列,提交截图. 错误回答 从A点开始遍历:0124-01324-0134-0324-034 从B点开始遍历 ...
- 大话数据结构 17:图的深度优先遍历和广度优先遍历
深度优先遍历 主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底-,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点 ...
- 图:图的邻接表创建、深度优先遍历和广度优先遍历代码实现
邻接表介绍 邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构比较较浪费存储空间.如果不想浪费存储空间,大家肯定会先到链表.需要空间的时候再才想内存去申请,同样适用于图 ...
- 图:图的邻接矩阵创建、深度优先遍历和广度优先遍历详解
邻接矩阵介绍 直接说,邻接矩阵是图的一种存储结构.那么图是什么呢?图是一种逻辑结构,和线性结构.树形结构.集合结构一样 是一种逻辑结构用来描述数据对象中的数据元素之间的关系.来看下图的定义:图(Gra ...
- 数据结构之图:邻接矩阵和邻接表、深度优先遍历和广度优先遍历
简介 线性表是一种线性结构,除了头结点和尾节点,线性表的每个元素都只有一个前取节点和一个后继节点.而树结构则相较于线性表更加复杂,它描述的关系为数据元素之间的父子关系,也是现实世界父子关系的缩影, 一 ...
- 多级树的深度优先遍历与广度优先遍历(Java实现)
目录 多级树的深度优先遍历与广度优先遍历(Java实现) 节点模型 深度优先遍历 广度优先遍历 多级树的深度优先遍历与广度优先遍历(Java实现) 深度优先遍历与广度优先遍历其实是属于图算法的一种,多 ...
- 数据结构—无向图创建邻接矩阵、深度优先遍历和广度优先遍历(C语言版)
无向图创建邻接矩阵.深度优先遍历和广度优先遍历 一.概念解析: (1)无向图: (2)邻接矩阵: 二.创建邻接矩阵: 三.深度遍历.广度遍历 (1)深度遍历概念: (2)广度遍历概念: 四.实例展示 ...
- 实现教材算法7.2利用邻接矩阵构造无向图的算法,在此基础上进行深度优先遍历和广度优先遍历。
软件学院实验报告 姓名: 学号: 专业: 年级: 课程名称 数据结构 实验名称 实验9.图的遍历 实验的准备阶段 实验内 ...
- 二叉树深度优先遍历和广度优先遍历
二叉树深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
二叉树是一种很重要的数据结构,对于二叉树的遍历,有深度优先遍历和广度优先遍历,深度优先遍历又有先序.中序.后续遍历,广度优先遍历就是按层遍历. 1. 深度优先遍历 深度优先遍历,也就是先序.中序.后续 ...
最新文章
- python 数据库支持sql_Python 对数据库进行SQL操作
- 关于在html中正常,在aspx中乱码的问题
- Python 操作 MySQL 数据库
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1095:数1的个数
- 如何查找历史线程阻塞原因_学习 Web Worker(js中的“多线程”)
- Spring MVC 4 - Hello World Tutorial
- 队列处理高并发_高并发架构消息队列面试题解析
- 微信秘笈之--微信多开
- jdk1.8中使用aspectjweaver报错 Invalid byte tag in constant pool 18
- 服务器分区有什么作用,MSR 分区有什么用_网站服务器运行维护
- C# async / await 任务超时处理
- Python最全学习路线
- 华硕FL5900U笔记本电脑重装win10专业版详细操作教程
- MockFlow线框图、原型软件
- 树莓派:GPIO/引脚/Pin 介绍
- 外刊逐句精读|《经济学人》:戒酒、吃素,禁食都有啥讲究?
- pip install lap出现问题
- java curl 使用方法_如何在Java中使用这个cURL POST请求?(Spotify API)
- 希腊字母表__手写 拍照版
- Blos查看计算机硬盘,怎么检查硬盘是否被电脑识别 进bios判断硬盘是否运行方法...
热门文章
- c++14 0 名字空间和条件编译
- 没学过JavaScript也能看懂的闭包解释
- C++ ORM ODB入门
- CentOS 6.5 yum安装mysql5.6或其他版本【默认yum只能安装mysql 5.1】 by jason
- 第二百一十六节,jQuery EasyUI,Spinner(微调)组件
- Linux中的cp命令老九门
- MySQL 5.6 关于登陆的初始化设置
- Nginx安全配置标准(for proxy)
- 使用 jQuery 避免鼠标双击
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析...