一、广度优先搜索
什么是广度优先搜索? 在给定图G=(V,E)后和一个特定的源顶点s的情况下,广度优先搜索,系统的探索G中的边,以期发现从s可以到达的所有顶点,并计算s到所有这些可达顶点之间的距离(即最少的边数)
广度优先搜索的作用?个人从定义理解就是,计算出s可以到达的所有顶点,并且计算出到这些顶点的距离(最短路径上的边数,如果边没有权重,这个结果将更有意义)。另一方面,通过广度优先搜索,我们可以判断一个无向图是否是连通图。
广度优先搜索算法:
1、算法导论书上实现BFS算法,本人用python实现。
代码介绍:类G是图的邻接表表示方式,这里是一个有向图,有10个顶点,G的vector数组存储每个顶点可出发的边。BFS函数:color数组存储每个顶点的颜色,parent数组存储每个顶点的父母,distance存储s到该顶点的距离,不可达填None
代码改进:这里可以BFS算法走完后,我们可以通过parent数组打印出,顶点到s的最短路径(可能有多个,在这里我们只能打印出一条,这是一个局限)。
算法分析:
运行时间O(V+E)V是顶点数,E是边数
额外存储 3*v
class G:
number = 10
vector=[]
time = 0
def __init__(self):
for n in range( 0,self.number):
print n
self.vector.append( [n*2%10,0])
return
def BFS(G1,s):
color = []
parent = []
distance = []
for n in range(0,G1.number):
color.append("white")
parent.append(None)
distance.append(None)
color[s] = "gray"
parent[s] = None
distance[s] = 0
que = [](注意这边使用数组做的一个队列:先进先出)
que.append(s)
while len(que) != 0:
u = que[0]
que = que[1:]
for item in G1.vector[u]:
if color[item] == "white":
color[item] = "gray"
distance[item]= distance[u] + 1
parent[item] = u
que.append(item)
color[u] = "black"
print distance
return
a1 = G()
BFS(a1,1)
2、算法导论习题:如果把迷宫看成一个连通的无向图,设计一条路径,走出迷宫?(各位大虾指教)
二、深度优先搜索
什么是深度优先搜索?简述:对每个可能的分支路径深入到不能再深入为止。
算法导论上定义:在深度优先搜索中,对于新发现的顶点,如果他还有以此为起点的而未探测到的边,就沿此边继续搜索下去。当顶点v的所有边都被探索过后,搜索将回朔到发现丁v有起始点的边。这一过程一直进行下去,知道发现从源顶点可达的所有顶点为止。
深度优先搜索的作用?1、深度优先搜索可以进行拓扑排序。 (拓扑排序对有向图意义比较大)2、可以判断一个有向无回图是否有回路 3、对边分类成 树边、反向边、正向边、交叉边(如果一个有向图有反向边,则该图有回路)
1、算法导论的 深度优先搜索算法:
代码介绍:类G通过邻接表方式标示图(详见上面定义),数组color存储节点颜色,表示节点状态;数组parent存储节点的父母;数组d存储节点的发现时间(发现节点为白色);数组f存储节点搜索结束时间(节点颜色变为黑色)。
代码改进:通过d、v两个数组,我们能够对G进行拓扑排序
算法分析:
O(v+E)
额外存储:4*V
def DFS(G1):
color = []
parent = []
d = []
f = []
for i in range(0,G1.number):
color.append("white")
parent.append(None)
d.append(-1)
f.append(-1)
for n in range (0,G1.number):
if color[n] == "white":
DFS_vist(G1,n,d,f,color,parent)
print d
print f
return
def DFS_vist(G1,n,d,f,color,parent):
color[n] = "gray"
G1.time = G1.time + 1
d[n] = G1.time
for v in G1.vector[n]:
if color[v] == "white":
parent[v] = n
DFS_vist(G1,v,d,f,color,parent)
color[n] = "black"
G1.time = G1.time + 1
f[n] = G1.time
return
a2 = G()
DFS(a2)
2、习题:不采用递归实现DFS算法(可参考广度优先搜索)
本人实现方法:
def DFS_2(G1):
G1.time = 0
color = []
parent = []
d = []
stack = []
f = []
for i in range(0,G1.number):
color.append("white")
parent.append(None)
d.append(-1)
f.append(-1)
stack.append(i)
while len(stack) > 0:
u = stack.pop()
vNext = None
if color[u] != "black":
for v in G1.vector[u]:
if color[v] == "white":
vNext = v
break;
else:
continue
if color[u] == "white":
G1.time = G1.time + 1
d[u] = G1.time
color[u] = "gray"
elif color[u] == "gray" and vNext == None:
G1.time = G1.time + 1
f[u] = G1.time
color[u] = "black"
if vNext != None:
color[vNext] = "gray"
G1.time = G1.time + 1
d[vNext] = G1.time
stack.append(u)
stack.append(vNext)
print d
print f
return
3、习题:如何证明一个有向图是单连通,即存在一条唯一的简单路径(路径上的顶点不重复),该路径经过所有顶点 。
一种假设解决方法:求出图存在的所有拓扑排序,找出相邻点之间有边(方向前指后)的拓扑排序,如果只有一条这种拓扑排序,则证明是单连通,否则不是。
三、拓扑排序
什么是拓扑排序?对有向无回图进行拓扑排序后,如果图G包含边(u,v),那么拓扑排序中u在v的前面
拓扑排序的作用?1、可以表达顶点之间的顺序,如果映射到实际情况中,能反应事物之前的先后顺寻(比如,先穿内衣再穿外套)
1、算法导论给出的拓扑排序算法:
对图进行深度优先搜索
在搜索过程中,如果一个顶点搜索结束(颜色变为black),则将顶点插入结果序列的最前端
最后这个结果序列就是图的拓扑排序
2、习题:另一种拓扑排序算法,重复寻找一个入度为0的顶点,将该顶点、以及所有的出边删除。解释如何来实现这一想法,才能使得它的运行时间为O(v+e)?如果G中包含回路,这个算法运行时会发生什么。
算法分析:
计算顶点入度,计算次数 E(边数)
寻找入读为0,比较次数V(顶点数)
while循环内部for循环执行次数:E
for循环其他部分:V
所以可以得出时间为O(E+v)
额外存储:3*V
def top_sort(G1):
#初始化入度表为0
inDegree = [0 for i in range(0,G1.number)]
#计算顶点入度
for n in range(0,G1.number):
for v in G1.vector[n]:
inDegree[v] = inDegree[v] + 1
print inDegree
stack = []
#将入度为0的压入stack
for n in range(0,G1.number):
if inDegree[n] == 0:
stack.append(n)
print stack
ret = []
while len(stack) != 0:
u = stack.pop()
ret.append(u)
for v in G1.vector[u]:
inDegree[v] = inDegree[v] - 1
if inDegree[v] == 0:
stack.append(v)
print ret
四、强连通分支(概念请参考上一篇)
1、算法导论给出的求解强连通分支算法:
scc算法
一通过DFS对图G进行拓扑排序
求G的转置图G^t
对转置图按照 第一步计算得出的拓扑顺序进行DFS搜索,每一次搜索发现的顶点组成的就是图G的最强连通分支
算法分析:两次DFS,详见 深度优先搜索介绍
2、在图中加入一条新边后,强连通分支数目如何变化?
如果新边在一个强连通分支内部:无变法
如果新边连接了两个强两通分支:则可能-1,或者不变化
3、证明一个有向图是半连通的,如果对于图G = (V,E),如果对于所有顶点u、v属于V,u可到达v或者v可到达u,则称为半连通。
先求解图的所有强连通分支,如果各个分支之间有桥梁边连接,则,该图为半连通