广度优先搜索

合集下载

信息学竞赛中的广度优先搜索算法

信息学竞赛中的广度优先搜索算法

信息学竞赛中的广度优先搜索算法广度优先搜索(Breadth-First Search,BFS)是一种常用的图搜索算法,广泛应用于信息学竞赛中。

本文将介绍广度优先搜索算法的原理、应用场景以及实现方法。

一、算法原理广度优先搜索算法是一种基于队列的搜索算法,通过逐层扩展搜索的方式,从起始节点开始,依次遍历其邻接节点,然后依次遍历邻接节点的邻接节点,直到找到目标节点或遍历完所有节点为止。

该算法的基本过程如下:1. 创建一个队列,并将起始节点加入队列;2. 从队列中取出首个节点,并标记为已访问;3. 遍历该节点的邻接节点,若未被标记为已访问,则将其加入队列;4. 重复步骤2和步骤3,直到队列为空或找到目标节点。

广度优先搜索算法可以用来解决一些与图相关的问题,比如最短路径问题、连通性问题等。

二、应用场景广度优先搜索算法在信息学竞赛中有广泛的应用,以下是一些常见的应用场景。

1. 连通性问题:判断图中两个节点是否连通。

通过广度优先搜索,可以从起始节点开始遍历图,找到目标节点即可判断其连通性。

2. 最短路径问题:找到两个节点之间的最短路径。

广度优先搜索每一层的遍历都是从起始节点到目标节点的可能最短路径,因此可以通过记录路径长度和路径信息,找到最短路径。

3. 迷宫问题:求解迷宫中的最短路径。

迷宫可以看作是一个图,起始位置为起始节点,终点位置为目标节点,通过广度优先搜索可以找到迷宫中的最短路径。

4. 可达性问题:判断一个节点是否可达其他节点。

通过广度优先搜索,可以从起始节点开始遍历图,标记所有可达节点,然后判断目标节点是否被标记。

三、实现方法广度优先搜索算法的实现可以使用队列来辅助完成。

以下是一个基于队列的广度优先搜索算法的伪代码示例:```BFS(start, target):queue = [start] // 创建一个队列,并将起始节点加入队列visited = set() // 创建一个集合,用于标记已访问的节点while queue is not emptynode = queue.pop(0) // 从队列中取出首个节点visited.add(node) // 标记节点为已访问if node == targetreturn True // 找到目标节点,搜索结束for neighbor in node.neighbors // 遍历节点的邻接节点if neighbor not in visitedqueue.append(neighbor) // 将邻接节点加入队列return False // 队列为空,未找到目标节点```四、总结广度优先搜索算法在信息学竞赛中是一种常用的算法,它通过逐层遍历的方式,能够快速的找到目标节点或解决与图相关的问题。

广度优先搜索的原理及应用是什么

广度优先搜索的原理及应用是什么

广度优先搜索的原理及应用是什么1. 原理广度优先搜索(Breadth-First Search, BFS)是一种图的遍历算法,它从图的起始顶点开始,逐层地向外探索,直到找到目标顶点或者遍历完整个图。

通过利用队列的数据结构,广度优先搜索保证了顶点的访问顺序是按照其距离起始顶点的距离递增的。

广度优先搜索的基本原理如下:1.选择一个起始顶点,将其加入一个待访问的队列(可以使用数组或链表实现)。

2.将起始顶点标记为已访问。

3.从队列中取出一个顶点,访问该顶点,并将其未访问过的邻居顶点加入队列。

4.标记访问过的邻居顶点为已访问。

5.重复步骤3和步骤4,直到队列为空。

广度优先搜索保证了先访问距离起始点近的顶点,然后才访问距离起始点远的顶点,因此可以用来解决一些问题,例如最短路径问题、连通性问题等。

2. 应用广度优先搜索在计算机科学和图论中有着广泛的应用,下面是一些常见的应用场景:2.1 最短路径问题广度优先搜索可以用来找出两个顶点之间的最短路径。

在无权图中,每条边的权值都为1,那么从起始顶点到目标顶点的最短路径就是通过广度优先搜索找到的路径。

2.2 连通性问题广度优先搜索可以用来判断两个顶点之间是否存在路径。

通过从起始顶点开始进行广度优先搜索,如果能够找到目标顶点,就说明两个顶点是连通的;如果搜索完成后仍然未找到目标顶点,那么两个顶点之间就是不连通的。

2.3 图的遍历广度优先搜索可以用来遍历整个图的顶点。

通过从起始顶点开始进行广度优先搜索,并在访问每个顶点时记录下访问的顺序,就可以完成对整个图的遍历。

2.4 社交网络分析广度优先搜索可以用来分析社交网络中的关系。

例如,在一个社交网络中,可以以某个人为起始节点,通过广度优先搜索找出与该人直接或间接连接的人,从而分析人际关系的密切程度、社区结构等。

2.5 网络爬虫广度优先搜索可以用来实现网络爬虫对网页的抓取。

通过从初始网页开始,一层层地向外发现新的链接,并将新的链接加入待抓取的队列中,从而实现对整个网站的全面抓取。

广度优先搜索

广度优先搜索
112源自FRONTREAR
一:交通图问题
表示的是从城市A到城市H 表示的是从城市A到城市H的交通图。从图中可以 看出,从城市A到城市H 看出,从城市A到城市H要经过若干个城市。现要 找出一条经过城市最少的一条路线。
分析该题
分析:看到这图很容易想到用邻接距阵来表示,0 分析:看到这图很容易想到用邻接距阵来表示,0表示能 走,1表示不能走。如图5 走,1表示不能走。如图5。
用数组合表示 8个城市的相互 关系
procedure doit; begin h:=0; d:=1; a.city[1]:='A'; a.pre[1]:=0; s:=['A']; repeat {步骤2} {步骤 步骤2} inc(h); {队首加一,出队} {队首加一 出队} 队首加一, for i:=1 to 8 do {搜索可直通的城市} {搜索可直通的城市 搜索可直通的城市} if (ju[ord(a.city[h])-64,i]=0)and ju[ord(a.city[h])-64,i]=0) not(chr(i+64) s)) ))then {判断城市是否走 (not(chr(i+64) in s))then {判断城市是否走 过} begin inc(d); {队尾加一,入队} {队尾加一 入队} 队尾加一, a.city[d]:=chr(64+i); a.pre[d]:=h; s:=s+[a.city[d]]; if a.city[d]='H' then out; end; until h=d; end; begin {主程序} {主程序 主程序} doit; end. 输出: 输出: H-F--A --A
深度优先搜索: 深度优先搜索:状态树

深度优先搜索和广度优先搜索

深度优先搜索和广度优先搜索

深度优先搜索和⼴度优先搜索 深度优先搜索和⼴度优先搜索都是图的遍历算法。

⼀、深度优先搜索(Depth First Search) 1、介绍 深度优先搜索(DFS),顾名思义,在进⾏遍历或者说搜索的时候,选择⼀个没有被搜过的结点(⼀般选择顶点),按照深度优先,⼀直往该结点的后续路径结点进⾏访问,直到该路径的最后⼀个结点,然后再从未被访问的邻结点进⾏深度优先搜索,重复以上过程,直⾄所有点都被访问,遍历结束。

⼀般步骤:(1)访问顶点v;(2)依次从v的未被访问的邻接点出发,对图进⾏深度优先遍历;直⾄图中和v有路径相通的顶点都被访问;(3)若此时图中尚有顶点未被访问,则从⼀个未被访问的顶点出发,重新进⾏深度优先遍历,直到图中所有顶点均被访问过为⽌。

可以看出,深度优先算法使⽤递归即可实现。

2、⽆向图的深度优先搜索 下⾯以⽆向图为例,进⾏深度优先搜索遍历: 遍历过程: 所以遍历结果是:A→C→B→D→F→G→E。

3、有向图的深度优先搜索 下⾯以有向图为例,进⾏深度优先遍历: 遍历过程: 所以遍历结果为:A→B→C→E→D→F→G。

⼆、⼴度优先搜索(Breadth First Search) 1、介绍 ⼴度优先搜索(BFS)是图的另⼀种遍历⽅式,与DFS相对,是以⼴度优先进⾏搜索。

简⾔之就是先访问图的顶点,然后⼴度优先访问其邻接点,然后再依次进⾏被访问点的邻接点,⼀层⼀层访问,直⾄访问完所有点,遍历结束。

2、⽆向图的⼴度优先搜索 下⾯是⽆向图的⼴度优先搜索过程: 所以遍历结果为:A→C→D→F→B→G→E。

3、有向图的⼴度优先搜索 下⾯是有向图的⼴度优先搜索过程: 所以遍历结果为:A→B→C→E→F→D→G。

三、两者实现⽅式对⽐ 深度优先搜索⽤栈(stack)来实现,整个过程可以想象成⼀个倒⽴的树形:把根节点压⼊栈中。

每次从栈中弹出⼀个元素,搜索所有在它下⼀级的元素,把这些元素压⼊栈中。

并把这个元素记为它下⼀级元素的前驱。

广度优先和深度优先的例子

广度优先和深度优先的例子

广度优先和深度优先的例子广度优先搜索(BFS)和深度优先搜索(DFS)是图遍历中常用的两种算法。

它们在解决许多问题时都能提供有效的解决方案。

本文将分别介绍广度优先搜索和深度优先搜索,并给出各自的应用例子。

一、广度优先搜索(BFS)广度优先搜索是一种遍历或搜索图的算法,它从起始节点开始,逐层扩展,先访问起始节点的所有邻居节点,再依次访问其邻居节点的邻居节点,直到遍历完所有节点或找到目标节点。

例子1:迷宫问题假设有一个迷宫,迷宫中有多个房间,每个房间有四个相邻的房间:上、下、左、右。

现在我们需要找到从起始房间到目标房间的最短路径。

可以使用广度优先搜索算法来解决这个问题。

例子2:社交网络中的好友推荐在社交网络中,我们希望给用户推荐可能认识的新朋友。

可以使用广度优先搜索算法从用户的好友列表开始,逐层扩展,找到可能认识的新朋友。

例子3:网页爬虫网页爬虫是搜索引擎抓取网页的重要工具。

爬虫可以使用广度优先搜索算法从一个网页开始,逐层扩展,找到所有相关的网页并进行抓取。

例子4:图的最短路径在图中,我们希望找到两个节点之间的最短路径。

可以使用广度优先搜索算法从起始节点开始,逐层扩展,直到找到目标节点。

例子5:推荐系统在推荐系统中,我们希望给用户推荐可能感兴趣的物品。

可以使用广度优先搜索算法从用户喜欢的物品开始,逐层扩展,找到可能感兴趣的其他物品。

二、深度优先搜索(DFS)深度优先搜索是一种遍历或搜索图的算法,它从起始节点开始,沿着一条路径一直走到底,直到不能再继续下去为止,然后回溯到上一个节点,继续探索其他路径。

例子1:二叉树的遍历在二叉树中,深度优先搜索算法可以用来实现前序遍历、中序遍历和后序遍历。

通过深度优先搜索算法,我们可以按照不同的遍历顺序找到二叉树中所有节点。

例子2:回溯算法回溯算法是一种通过深度优先搜索的方式,在问题的解空间中搜索所有可能的解的算法。

回溯算法常用于解决组合问题、排列问题和子集问题。

例子3:拓扑排序拓扑排序是一种对有向无环图(DAG)进行排序的算法。

广度优先搜索和深度优先搜索有何区别

广度优先搜索和深度优先搜索有何区别

广度优先搜索和深度优先搜索有何区别在计算机科学和算法领域中,广度优先搜索(BreadthFirst Search,简称 BFS)和深度优先搜索(DepthFirst Search,简称 DFS)是两种常见且重要的图或树的遍历算法。

它们在解决各种问题时都有着广泛的应用,但在搜索策略和特点上存在着显著的差异。

让我们先来了解一下广度优先搜索。

想象一下你正在一个迷宫中,你从入口开始,先探索与入口相邻的所有房间,然后再依次探索这些相邻房间相邻的房间,以此类推。

这就是广度优先搜索的基本思路。

广度优先搜索是以逐层的方式进行的。

它首先访问起始节点,然后依次访问起始节点的所有邻接节点,接着再访问这些邻接节点的邻接节点,就像在平静的湖面上泛起的层层涟漪。

这种搜索方式确保在访问更深层次的节点之前,先访问同一层次的所有节点。

在实现广度优先搜索时,通常会使用一个队列(Queue)数据结构。

将起始节点入队,然后循环取出队列头部的节点,并将其未访问过的邻接节点入队,直到队列为空。

这种方式保证了搜索的顺序是按照层次进行的。

广度优先搜索的一个重要应用是在寻找最短路径问题上。

因为它先访问距离起始节点近的节点,所以如果存在最短路径,它往往能够更快地找到。

例如,在地图导航中,要找到从一个地点到另一个地点的最短路线,广度优先搜索就可能是一个不错的选择。

接下来,我们看看深度优先搜索。

如果说广度优先搜索是逐层展开,那么深度优先搜索就像是一个勇敢的探险家,沿着一条路径一直走下去,直到走到尽头或者无法继续,然后才回溯并尝试其他路径。

深度优先搜索通过递归或者使用栈(Stack)来实现。

从起始节点开始,不断深入访问未访问过的邻接节点,直到无法继续,然后回溯到上一个未完全探索的节点,继续探索其他分支。

深度优先搜索在探索复杂的树形结构或者处理递归问题时非常有用。

比如在检查一个表达式是否合法、遍历一个复杂的文件目录结构等方面,深度优先搜索能够发挥其优势。

广度优先搜索算法利用广度优先搜索解决的最短路径问题

广度优先搜索算法利用广度优先搜索解决的最短路径问题

广度优先搜索算法利用广度优先搜索解决的最短路径问题广度优先搜索算法(BFS)是一种图算法,用于解决最短路径问题。

其主要思想是从起始节点开始,不断扩展和访问其邻居节点,直到找到目标节点或者遍历完所有节点。

BFS算法可以用于解决许多问题,其中包括最短路径问题。

下面将介绍广度优先搜索算法的基本原理及其应用于最短路径问题的具体步骤。

同时,通过示例来进一步说明算法的执行过程和实际应用。

一、广度优先搜索算法原理广度优先搜索算法是一种层次遍历的算法,它从起始节点开始,按照距离递增的顺序,依次遍历节点。

在遍历的过程中,任意两个节点之间的距离不超过2,因此,BFS算法可以用于求解最短路径问题。

二、广度优先搜索算法的具体步骤1. 创建一个队列,用于存储待访问的节点。

2. 将起始节点放入队列中,并将其标记为已访问。

3. 当队列不为空时,执行以下步骤:a. 从队列中取出一个节点。

b. 访问该节点,并根据需求进行相应操作。

c. 将该节点的所有未访问过的邻居节点放入队列中,并将它们标记为已访问。

d. 重复步骤a~c,直到队列为空。

4. 完成以上步骤后,如果找到目标节点,则算法终止;否则,表示目标节点不可达。

三、广度优先搜索算法在最短路径问题中的应用最短路径问题是指从一个节点到另一个节点的最短路径,其长度可以通过广度优先搜索算法得到。

考虑以下示例:假设有一个迷宫,迷宫由多个格子组成,其中一些格子是墙壁,不可通过,而其他格子可以自由通行。

任务是找到从起始格子到达目标格子的最短路径。

利用广度优先搜索算法解决最短路径问题的具体步骤如下:1. 创建一个队列,并将起始格子放入队列中。

2. 将起始格子标记为已访问。

3. 当队列不为空时,执行以下步骤:a. 从队列中取出一个格子。

b. 如果该格子是目标格子,则算法终止。

c. 否则,获取该格子的邻居格子,并将未访问过的邻居格子放入队列中。

d. 将该格子的邻居格子标记为已访问。

e. 重复步骤a~d,直到队列为空。

广度优先搜索优化方法

广度优先搜索优化方法

广度优先搜索优化方法广度优先搜索(BFS)是一种常用的图搜索算法,它从起始节点开始,逐层地遍历图中的节点,直到找到目标节点或者遍历完所有可达节点为止。

然而,在面对大规模图数据时,BFS可能会面临内存占用较大、计算效率较低的问题。

因此,为了提高BFS的性能,我们可以采用一些优化方法。

一、使用位图数据结构在BFS中,我们需要标记节点是否已经被访问过,以防止重复遍历和死循环。

传统的做法是使用一个数组或者哈希表来记录节点的访问状态,但是这样会消耗大量的内存空间。

为了减少内存开销,可以使用位图数据结构来代替数组或者哈希表。

位图只需要1比特的空间来表示一个节点的访问状态,相比之下,数组和哈希表需要更多的内存空间。

通过位图数据结构,可以大大降低内存占用量,从而提高BFS 算法的效率。

二、使用双端队列在BFS中,我们需要使用队列来保存待遍历的节点。

传统的做法是使用一个普通的队列数据结构,但是在一些场景下,普通队列的性能可能不够高。

为了提高性能,可以使用双端队列(deque)来代替普通队列。

双端队列支持在队列的两端进行插入和删除操作,相比之下,普通队列只支持在队尾插入和在队头删除。

通过使用双端队列,可以在需要的时候从队列的头部或者尾部插入和删除节点,从而提高BFS 算法的效率。

三、剪枝策略在BFS中,我们可能会遍历大量的节点,其中很多节点并不是我们要找的目标节点。

为了减少不必要的遍历,可以采用一些剪枝策略。

常见的剪枝策略包括:1. 判断节点是否满足某个条件,如果不满足,则不继续遍历下去;2. 判断节点是否已经被访问过,如果已经被访问过,则不继续遍历下去;3. 判断节点是否在禁止访问的列表中,如果在列表中,则不继续遍历下去。

通过采用合理的剪枝策略,可以减少无效的遍历,从而提高BFS算法的效率。

四、并行计算在面对大规模图数据时,BFS的计算过程可能非常耗时。

为了缩短计算时间,可以考虑采用并行计算的方式来进行BFS。

并行计算可以将大规模的计算任务划分成多个小任务,并行地进行计算。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

广度优先搜索(BFS)算法宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。

Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。

已知图G=(V,E)和一个源顶点s,宽度优先搜索以一种系统的方式探寻G的边,从而“发现”s所能到达的所有顶点,并计算s到所有这些顶点的距离(最少边数),该算法同时能生成一棵根为s且包括所有可达顶点的宽度优先树。

对从s可达的任意顶点v,宽度优先树中从s到v的路径对应于图G中从s到v的最短路径,即包含最小边数的路径。

该算法对有向图和无向图同样适用。

之所以称之为宽度优先算法,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点。

为了保持搜索的轨迹,宽度优先搜索为每个顶点着色:白色、灰色或黑色。

算法开始前所有顶点都是白色,随着搜索的进行,各顶点会逐渐变成灰色,然后成为黑色。

在搜索中第一次碰到一顶点时,我们说该顶点被发现,此时该顶点变为非白色顶点。

因此,灰色和黑色顶点都已被发现,但是,宽度优先搜索算法对它们加以区分以保证搜索以宽度优先的方式执行。

若(u,v)∈E且顶点u为黑色,那么顶点v要么是灰色,要么是黑色,就是说,所有和黑色顶点邻接的顶点都已被发现。

灰色顶点可以与一些白色顶点相邻接,它们代表着已找到和未找到顶点之间的边界。

在宽度优先搜索过程中建立了一棵宽度优先树,起始时只包含根节点,即源顶点s.在扫描已发现顶点u的邻接表的过程中每发现一个白色顶点v,该顶点v及边(u,v)就被添加到树中。

在宽度优先树中,我们称结点u是结点v的先辈或父母结点。

因为一个结点至多只能被发现一次,因此它最多只能有--个父母结点。

相对根结点来说祖先和后裔关系的定义和通常一样:如果u处于树中从根s到结点v 的路径中,那么u称为v的祖先,v是u的后裔。

下面的宽度优先搜索过程BFS假定输入图G=(V,E)采用邻接表表示,对于图中的每个顶点还采用了几种附加的数据结构,对每个顶点u∈V,其色彩存储于变量color[u]中,结点u的父母存于变量π[u]中。

如果u没有父母(例如u=s或u 还没有被检索到),则π[u]=NIL,由算法算出的源点s和顶点u之间的距离存于变量d[u]中,算法中使用了一个先进先出队列Q来存放灰色节点集合。

其中head[Q]表示队列Q的队头元素,Enqueue(Q,v)表示将元素v入队,Dequeue(Q)表示对头元素出队;Adj[u]表示图中和u相邻的节点集合。

procedure BFS(G,S);begin1. for 每个节点u∈V[G]-{s} dobegin2. color[u]←White;3. d[u]←∞;4. π[u]←NIL;end;5. color[s]←Gray;6. d[s]←0;7. π[s]←NIL;8. Q←{s}9. while Q≠φ dobegin10. u←head[Q];11. for 每个节点v∈Adj[u] do12. if color[v]=White thenbegin13. color[v]←Gray;14. d[v]←d[v]+1;15. π[v]←u;16. Enqueue(Q,v);end;17. Dequeue(Q);18. color[u]←Black;end;end;图1展示了用BFS在例图上的搜索过程。

黑色边是由BFS产生的树枝。

每个节点u内的值为d[u],图中所示的队列Q是第9-18行while循环中每次迭代起始时的队列。

队列中每个结点下面是该结点与源结点的距离。

图1 BFS在一个无向图上的执行过程过程BFS按如下方式执行,第1-4行置每个结点为白色,置d[u]为无穷大,每个结点的父母置为NIL,第5行置源结点S为灰色,即意味着过程开始时源结点已被发现。

第6行初始化d[s]为0,第7行置源结点的父母结点为NIL,第8行初始化队列0,使其仅含源结点s,以后Q队列中仅包含灰色结点的集合。

程序的主循环在9-18行中,只要队列Q中还有灰色结点,即那些已被发现但还没有完全搜索其邻接表的结点,循环将一直进行下去。

第10行确定队列头的灰色结点为u。

第11-16行的循环考察u的邻接表中的每一个顶点v。

如果v是白色结点,那么该结点还没有被发现过,算法通过执行第13-16行发现该结点。

首先它被置为灰色,距离d[v]置为d[u]+1,而后u被记为该节点的父母,最后它被放在队列Q的队尾。

当结点u的邻接表中的所有结点都被检索后,第17-18行使u弹出队列并置成黑色。

分析在证明宽度优先搜索的各种性质之前,我们先做一些相对简单的工作——分析算法在图G=(V,E)之上的运行时间。

在初始化后,再没有任何结点又被置为白色。

因此第12行的测试保证每个结点至多只能迸人队列一次,因而至多只能弹出队列一次。

入队和出队操作需要O(1)的时间,因此队列操作所占用的全部时间为O(V),因为只有当每个顶点将被弹出队列时才会查找其邻接表,因此每个顶点的邻接表至多被扫描一次。

因为所有邻接表的长度和为Q(E),所以扫描所有邻接表所花费时间至多为O(E)。

初始化操作的开销为O(V),因此过程BFS的全部运行时间为O(V+E),由此可见,宽度优先搜索的运行时间是图的邻接表大小的一个线性函数。

最短路径在本部分的开始,我们讲过,对于一个图G=(V,E),宽度优先搜索算法可以得到从已知源结点s∈V到每个可达结点的距离,我们定义最短路径长度δ(s,v)为从顶点s到顶点v的路径中具有最少边数的路径所包含的边数,若从s到v没有通路则为∞。

具有这一距离δ(s,v)的路径即为从s到v的最短路径(后文我们将把最短路径推广到赋权图,其中每边都有一个实型的权值,一条路径的权是组成该路径所有边的权值之和,目前讨论的图都不是赋权图)。

在证明宽度优先搜索计算出的就是最短路径长度之前,我们先看一下最短路径长度的一个重要性质。

引理1设G=(V,E)是一个有向图或无向图,s∈V为G的任意一个结点,则对任意边(u,v)∈E,δ(s,v)≤δ(s,u)+1证明:如果从顶点s可达顶点u,则从s也可达v。

在这种情况下从s到v的最短路径不可能比从s到u的最短路径加上边(u,v)更长,因此不等式成立;如果从s不可达顶点u,则δ(s,v)=∞,不等式仍然成立。

我们试图说明对每个顶点v∈V,BFS过程算出的d[v]=δ(s,v),下面我们首先证明d[v]是δ(s,v)的上界。

引理2设G=(V,E)是一个有向或无向图,并假设算法BFS从G中一已知源结点s∈V 开始执行,在执行终止时,对每个顶点v∈V,变量d[v]的值满足:d[v]≥δ(s,v)。

证明:我们对一个顶点进入队列Q的次数进行归纳,我们归纳前假设在所有顶点v∈V,d[v]≥δ(s,v)成立。

归纳的基础是BFS过程第8行当结点s被放入队列Q后的情形,这时归纳假设成立,因为对于任意结点v∈V-{s},d[s]=0=δ(s,s)且d[v]=∞≥δ(s,v)。

然后进行归纳,考虑从顶点u开始的搜索中发现一白色顶点v,按归纳假设,d[u]≥δ(s,u)。

从过程第14行的赋值语句以及引理1可知d[v]=d[u]+1≥δ(s,u)+1≥δ(s,v)然后,结点v被插入队列Q中。

它不会再次被插入队列,因为它已被置为灰色,而第13-16行的then子句只对白色结点进行操作,这样d[v]的值就不会改变,所以归纳假设成立。

为了证明d[v]=δ(s,v),首先我们必须更精确地展示在BFS执行过程中是如何对队列进行操作的,下面一个引理说明无论何时,队列中的结点至多有两个不同的d值。

引理3假设过程BFS在图G=(V,E)之上的执行过程中,队列Q包含如下结点<v1,v2,...,v r>,其中v1是队列Q的头,v r是队列的尾,则d[v i]≤d[v1]+1且d[v i]≤d[v i+1], i=1,2,..,r-1。

证明:证明过程是对队列操作的次数进行归纳。

初始时,队列仅包含顶点s,引理自然正确。

下面进行归纳,我们必须证明在压入和弹出一个顶点后引理仍然成立。

如果队列的头v1被弹出队列,新的队头为v2(如果此时队列为空,引理无疑成立),所以有d[v r]≤d[v1]+1≤d[v2]+1,余下的不等式依然成立,因此v2为队头时引理成立。

要插入一个结点入队列需仔细分析过程BFS,在BFS的第16行,当顶点v加入队列成为v r+1时,队列头v1实际上就是正在扫描其邻接表的顶点u,因此有d[v r+1]=d[v]=d[u]+1=d[v1]+1,这时同样有d[v r]≤d[v1]+1=d[u]+1=d[v]=d[v r+1],余下的不等式d[v r]≤d[v r+1]仍然成立,因此当结点v插入队列时引理同样正确。

现在我们可以证明宽度优先搜索算法能够正确地计算出最短路径长度。

定理1 宽度优先搜索的正确性设G=(V,E)是一个有向图或无向图,并假设过程BFS从G上某顶点s∈V开始执行,则在执行过程中,BFS可以发现源结点s可达的每一个结点v∈V,在运行终止时,对任意v∈V,d[v]=δ(s,v)。

此外,对任意从s可达的节点v≠s,从s到v的最短路径之一是从s到π[v]的最短路径再加上边(π[v],v)。

证明:我们先证明结点v是从s不可达的情形。

由引理2,d[v]≥δ(s,v)=∞,根据过程第14行,顶点v不可能有一个有限的d[v]值,由归纳可知,不可能有满足下列条件的第一个顶点存在:该顶点的d值被过程的第14行语句置为∞,因此仅对有有限d值的顶点,第14行语句才会被执行。

所以若v是不可达的话,它将不会在搜索中被发现。

证明主要是对由s可达的顶点来说的。

设V k表示和s距离为k的顶点集合,即V k={v∈V:δ(s,v)=k}。

证明过程为对k进行归纳。

作为归纳假设,我们假定对于每一个顶点v∈V k,在BFS的执行中只有某一特定时刻满足:▪结点v为灰色;▪d[v]被置为k;▪如果v≠s,则对于某个u∈V k-1,π[v]被置为u;▪v被插入队列Q中;正如我们先前所述,至多只有一个特定时刻满足上述条件。

归纳的初始情形为k=0,此时V0={s},因为显然源结点s是唯一和s距离为0的结点,在初始化过程中,s被置为灰色,d[s]被置为0,且s被放人队列Q中,所以归纳假设成立。

下面进行归纳,我们须注意除非到算法终止,队列Q不为空,而且一旦某结点u 被插入队列,d[u]和π[u]都不再改变。

根据引理3可知如果在算法过程中结点按次序v1,v2,...,v r被插入队列,那么相应的距离序列是单调递增的:d[v i]≤d[v i+1],i=1,2,...,r-1。

相关文档
最新文档