图论-搜索算法(BFS和DFS)

广度优先搜索

算法介绍

英文为 Breadth-First Search, BFS。其宗旨是从源点开始,逐步向外扩散,如图所示。

在这里插入图片描述

用到三个数组:

  • c o l o r [ u ] color[u] color[u]
    • WHITE \text{WHITE} WHITE:表示该点尚未搜索到
    • GREY \text{GREY} GREY:表示该点正在搜索
    • BLACK \text{BLACK} BLACK:表示该点搜索结束
  • p r e d [ u ] pred[u] pred[u]:表示点 u u u在搜索中的前驱顶点(predecesor)
  • d i s t [ u ] dist[u] dist[u]:表示点 u u u到源点的距离

算法:广度优先搜索
输入:图 G G G
输出:无
对于图中每个点 u u u,置 c o l o r [ u ] = WHITE color[u]=\text{WHITE} color[u]=WHITE,置 p r e d [ u ] = NULL pred[u]=\text{NULL} pred[u]=NULL
对于图中每个点 u u u,如果 c o l o r [ u ] = WHITE color[u]=\text{WHITE} color[u]=WHITE,调用 BFSVisit ( u ) \text{BFSVisit}(u) BFSVisit(u)

有多少个连通分支,以下算法就会被调用多少次:

算法 BFSVisit \text{BFSVisit} BFSVisit
输入:图 G G G,点 s s s
输出:无
c o l o r [ s ] = GREY color[s]=\text{GREY} color[s]=GREY
d i s t [ s ] = 0 dist[s]=0 dist[s]=0
初始化队列 Q Q Q 为空队列,并将 s s s 加入队列 Q Q Q
Q Q Q 不为空时:

队首元素 u u u出列
u u u的所有邻接顶点 v ∈ a d j [ u ] v\in adj[u] vadj[u]

c o l o r [ v ] = WHITE color[v]=\text{WHITE} color[v]=WHITE

c o l o r [ v ] = GREY color[v]=\text{GREY} color[v]=GREY
d [ v ] = d [ u ] + 1 d[v]=d[u]+1 d[v]=d[u]+1
p r e d [ v ] = u pred[v]=u pred[v]=u
v v v 加入 Q Q Q 队尾

c o l o r [ u ] = BLACK color[u]=\text{BLACK} color[u]=BLACK

时间复杂度分析

  • 对于每个顶点 u u u,我们需要查看其颜色,并对其所有邻接顶点 v v v进行操作,因此复杂度为 O ( 1 + d e g r e e ( u ) ) O(1+degree(u)) O(1+degree(u))
  • 总复杂度为 ∑ u ∈ V O ( 1 + d e g r e e ( u ) ) = O ( V + 2 E ) = O ( V + E ) \sum\limits_{u\in V}O(1+degree(u))=O(V+2E)=O(V+E) uVO(1+degree(u))=O(V+2E)=O(V+E)(用到握手定理)

应用

  • 无权图的单源最短路径
    • 由BFS得到的 d i s t [ u ] dist[u] dist[u]是源点 s s s到顶点 u u u的单源最短距离
    • 只能用于无权图,对于带权图需要使用Dijkstra算法或者Floyd算法
  • 寻找连通分支数量

深度优先搜索

算法介绍

英文为 Depth-First Search, DFS。算法思想是一条道走到底,然后再回头走其他分支,其实质是一种贪心策略

用到四个数组:

  • c o l o r [ u ] color[u] color[u]
    • WHITE \text{WHITE} WHITE:表示该点尚未搜索到
    • GREY \text{GREY} GREY:表示该点正在搜索
    • BLACK \text{BLACK} BLACK:表示该点搜索结束
  • p r e d [ u ] pred[u] pred[u]:表示点 u u u在搜索中的前驱顶点(predecesor)。
  • d [ u ] d[u] d[u]:表示点 u u u被发现的时间。它和 f [ u ] f[u] f[u]都是为了便于后续分析而打上的时间戳。
  • f [ u ] f[u] f[u]:表示点 u u u完成搜索的时间。

算法:深度优先搜索
输入:图 G G G
输出:无
对于图中每个点 u u u,置 c o l o r [ u ] = WHITE color[u]=\text{WHITE} color[u]=WHITE,置 p r e d [ u ] = NULL pred[u]=\text{NULL} pred[u]=NULL
置全局变量 t i m e = 0 time = 0 time=0
对于图中每个点 u u u,如果 c o l o r [ u ] = WHITE color[u]=\text{WHITE} color[u]=WHITE,调用 DFSVisit ( u ) \text{DFSVisit}(u) DFSVisit(u)

有多少个连通分支,以下算法就会被调用多少次:

算法 DFSVisit \text{DFSVisit} DFSVisit
输入:图 G G G,点 u u u
输出:无
c o l o r [ u ] = GREY color[u]=\text{GREY} color[u]=GREY
t i m e = t i m e + 1 time = time + 1 time=time+1
d [ u ] = t i m e d[u]=time d[u]=time
u u u的所有邻接顶点 v ∈ a d j [ u ] v\in adj[u] vadj[u]

c o l o r [ v ] = WHITE color[v]=\text{WHITE} color[v]=WHITE

p r e d [ v ] = u pred[v]=u pred[v]=u
调用 DFSVisit ( v ) \text{DFSVisit}(v) DFSVisit(v)

c o l o r [ u ] = BLACK color[u]=\text{BLACK} color[u]=BLACK
t i m e = t i m e + 1 time = time + 1 time=time+1
f [ u ] = t i m e f[u]=time f[u]=time

时间复杂度分析

与BFS相同,均需要对每个顶点和其邻接顶点进行遍历,因此也为 O ( V + E ) O(V+E) O(V+E)

算法的性质

深度优先树

以算法中得到的 p r e d [ u ] pred[u] pred[u]数组,可以构建一棵以前驱顶点为父节点的树,称为深度优先树。深度优先树是原图 G G G的一个子图。

  • 树边(tree edge):深度优先树中的边。
  • 后向边(back edge):它的两顶点在深度优先树中是祖先和后代节点的关系,但不是父子节点关系。

定理:无向图中的边,不是树边就是后向边。
即:无向图中的边的两个端点一定是DFS搜索中的祖先和后代,不存在两条边的两个端点之间没有任何直接或间接前驱/后继关系。
证明:这个定理的正确性是显然的。令 ( u , v ) (u,v) (u,v) G G G中的任意一条边,不妨设 d [ u ] < d [ v ] d[u]<d[v] d[u]<d[v],即 u u u被发现的时候, v v v还没被发现。那么,根据DFS算法, v v v一定在以 u u u为根节点的子树上,故二者必有祖先和后代关系。

括号化定理

括号化定理揭示了 d [ u ] d[u] d[u] f [ u ] f[u] f[u]时间戳的结构。如图所示,我们在DFS算法中的两个时间戳数组可以绘成如下的甘特图:

在这里插入图片描述

它具有以下的性质:

  • 每个时间点都是一个时间戳区间的端点。
  • u u u节点是 v v v节点的后代(descendent)当且仅当 v v v的区间包含 u u u的区间; u u u节点是 v v v节点的祖先(ancestor)当且仅当 v v v的区间是 u u u的区间的子区间(subinterval)。
  • u u u节点和 v v v节点是不连接的(unrelated),当且仅当 u u u v v v的区间没有交集(disjoint)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值