算法导论 Exercises 22.5(转载)

Exercises 22.5 - 算法导论.英文第3版 

最近看书的同时, 感觉一些练习缺少参考, 所以按部分总结了自己的解答, 也能够强化学习过程. 
如有不足或疑问, 欢迎指正. 
Exercises 22.5-1
How can the number of strongly connected components of a graph change if a new
edge is added?
可以将每个强连通组件当作一个顶点, 组成强连通图, 图内顶点数量即强连通组件数量.
如果新增加的边在顶点内部(即指向自己), 或者重复已有顶点间的边, 则数量没变化. 
如果新增加的边使图形成环,  这样环内顶点组成一个新的强连通组件, 所以数量减少N, N = (环内顶点数量 - 1).
 
 
Exercises 22.5-2
Show how the procedure STRONGLY-CONNECTED-COMPONENTS works on the
graph of Figure 22.6. Specifically, show the finishing times computed in line 1 and
the forest produced in line 3. Assume that the loop of lines 5–7 of DFS considers
vertices in alphabetical order and that the adjacency lists are in alphabetical order.
 
 
按照字母排序的循环和邻接表, 可得出第一次DFS访问顶点顺序, 如下
(q   (s (v (w, w) v) s)   (t (x (z, z) x)  (y, y) t)   q)   (r (u, u) r)   
 
finishing time: f(r) 20, f(u) 19, r(q) 16, f(t) 15, f(y) 14,
                     f(x) 12, f(z) 11, f(s) 7, f(v) 6, f(w) 5.
 
根据 finishing time 降序排列, 并倒转上图中的边, 第二次DFS访问顶点顺序, 如下
(r, r) *  (u, u) *  (q (y (t, t) y) q) *  (x (z, z) x) *  (s (w (v, v) w) s)
每个不相关括号(用*间隔)内的顶点, 代表 line 3 生成的树(即强连通组件)
 

ANSWER:DFS(G)森林:(其中红色为树边)

强连通分量结果:

 
Exercises 22.5-3
Professor Bacon claims that the algorithm for strongly connected components
would be simpler if it used the original (instead of the transpose) graph in the
second depth-first search and scanned the vertices in order of increasing finishing
times. Does this simpler algorithm always produce correct results?
 
设想对上图应用指定的升序式算法,  图中有A, B, C 三个顶点, A->B, B->A, B->C 三条边.
如果首次 DFS 从 B 开始, 先向 A 遍历, 则访问顶点顺序为 (B  (A, A)   (C, C)  B)
升序排列 finishing time 是 A, C, B. 这样第二次进行 DFS 则应从 A 开始, 该算法
结果显示 A, B, C 是一个强连通组件, 而实际情况不是如此.
该算法不能保证通用性, 只有在选择特殊顶点作为起始点, 以及规定邻接表顺序的情况下,
结果才有可能是正确的. 
 
 
Exercises 22.5-4
Prove that for any directed graph G, we have (( GT)SCC)T = (G)SCC. That is, the
transpose of the component graph of GT is the same as the component graph of G.
在图 G 中, 同一组件中的顶点可以互相连通. 而图 GT 中, 组件中的边虽然反转,
但其顶点仍可以互相连通, 这方面是不受影响的, 组件之间的边全部反转, 同样不会形成
新的组件. 所以 ((GT)SCC)T = (G)SCC, 即 GT 和 G 的强连通组件相同.
 
 
Exercises 22.5-5
Give an O (V + E)-time algorithm to compute the component graph of a directed
graph G = (V, E). Make sure that there is at most one edge between two vertices
in the component graph your algorithm produces.
 
(1) first DFS (G)            
            if v finish 
                orderList.push_front(v)  // orderList 是 finishing time 降序队列
时间 O(V + E)
(2) for each v in V
          for each x in v.adj
               x.adj.push_back(v)
即求 GT 时间 O(V + E)
(3) second DFS (GT)
          for v in order of orderList
               map v to scc  // scc 是强连通组件
               for each x in v.adj
                    if x.color = COLOR_BLACK  // 代表这条边(v, x)是强连通组件间的边
                         if x non-exist in scc.adj  // 在DFS(GT)期间总搜索时间 O(E)
                              scc.adj.push_back(x) 
 
即求 scc 和 scc.adj 时间 O(V + E), 所以算法时间复杂度 O(V + E).
   即:

(1)利用STRONGLY-CONNECTED-COMPONENTS(G)将结点分类,给每个分量中的结点赋予一个相同的标号,时间为O(V+E)。

(2)将同属一个分量的结点在分量图中记录在一起。

(3)对每个分量中每个结点遍历,记录每个分量中的结点向其他分量发出的边,并在分量图中补上。时间复杂度为O(V+E),但需要O(V)空间来记录分量图的边以避免出现重合的边。

           
 
Exercises 22.5-6
Given a directed graph G = (V, E), explain how to create another graph G' = (V, E') 
such that (a) G' has the same strongly connected components as G, (b) G'
has the same component graph as G, and (c) E' is as small as possible. Describe a
fast algorithm to compute G'
 
(1) 确定每个SCC顶点集合, 以及SCC间所有边集合 Es(不包含SCC内的边), 时间 O (V + E)
(2) 每个SCC内假设有点 v1, v2, ..., vn, 使其形成环 v1-> v2, v2->v3, ..., vn->v1, 时间 O (V)
(3) 这里假设 SCC 数量是 N, 生成 N * N 矩阵. 对 Es 中边 (vi , vj), 假设 vi 属于 SCCi , vj 属于 SCCj. 
如果 N[SCCi][SCCj] == 0, 则将 (vi, vj) 保存到 E' 中, 如果 N[SCCi][SCCj] == 1, 则跳过该边. 
依次计算 Es 中所有边, 此处时间 O(E'),  而 O(E') < O(E), 所以算法时间复杂度 O(V + E)
 即:

(1)利用强连通分量算法区分出不同的分量,并将分量图计算出。

(2)对于每个分量,找出同一分量中的每个结点,然后用一个简单的环连通每个结点。根据分量图的边给不同连通分量之间增加一条边(在一连通分量中随意寻找某一结点连接另一连通分量中的随意一个结点)。

 
Exercises 22.5-7
A directed graph G = (V, E) is semiconnected  if, for all pairs of vertices u, v ∈ V, 
we have u ~> v or v ~> u. Give an efficient algorithm to determine whether
or not G is semiconnected. Prove that your algorithm is correct, and analyze its
running time.
 

半连通的定义,有向图G(V,E),任意两个不同的点u、v,u有一条路径可达v或者v有一条路径可达u,从定义中可以看出,强连通图一定是半连通的。

引理:有向无环图G(V,E),G是半连通的当且仅当有一条路径,这条路径上有图G中所有点。

证明:充分性很显然,如果有这样一条路径,则任意两个点之间都有一条路径。

必要性,有向无环图,可以对其进行拓扑排序得到一个拓扑序列,拓扑序列中任意两个相邻的结点u,v,由半连通的定义可知,要么v~u,要么u~v,以下为图G的拓扑序列。

.....u,v................

(1) v~u,即有一条v到u的路径,而根据拓扑排序的属性,任意一条边只能从左边到右边,故从v无论如何都不能到达u

(2)u~v,即有一条从u到v的路径,如果没有边(u,v),u只能指向v之后的结点,根据拓扑排序的属性,任意一条边只能从左边到右边,故u不到达到v与半连通矛盾,故一定存在边(u,v)。

与是拓扑序列的任意两个相邻结点之间均有边,则这个拓扑序列就是这样的一条路径,其中包含图G的所有结点。

 对于任意图G,只需要将其转化为有向无环图(DAG),即通过强连通分支算法获取图G的连通分支图GSCC,分支图GSCC一定是有向无环图,故可以使用引理来确定是否为半连通。使用kosaraju 算法,因为此算法第二次DFS正好得到GSCC的拓扑序列,然后只要验证相邻的结点是否均有边即可。

强连通组件算法, 按第 2 次 DFS(GT) 强连通组件生成顺序编号, 假设是 SCC1, SCC2, ..., SCCn
如果存在边 (SCC1, SCC2), (SCC2, SCC3), ..., (SCCn-1, SCCn) , 即组件间边形成线性的链, 
则图 G 是 semiconnected. 稍后详细解释.
(1) 强连通组件图算法, 时间 O(V+E)
(2) 按强连通组件 SCC 顺序编号, 假设是SCC1, SCC2, ..., SCCn, 并求出组件 SCC 的邻接表, 
这步骤可以在 (1) 中完成, 所以时间 O(V+E)
(3) 遍历 SCC 邻接表, 如果对于范围 i = 1, 2, ..., n-1, 强连通组件SCCi.adj 中存在 SCCi+1 , 
既含有边 (SCCi, SCCi+1), 强连通组件图是线性链, 则 G = (V, E) 是 semiconnected, 时间 O(V+E).
详细解释, 按算法理论的支持, SCCi+1 不存在到SCCi 的边, 如果没有 (SCCi, SCCi+1), 
则两者均无法到达对方, 即不符合 G 是 semiconnected 的概念. 算法时间复杂度 O(V+E)
 
即:先运行强连通分量算法,按照第二次DFS结点搜索顺序给连通分量按升序标号(1~k),并生成分量图SCC(G)。在分量图SCC(G)中,由于标号为 i+1 的连通分量不可能指向标号为 i 的连通分量,所以只需要从1~k按顺序检测是否存在(1, 2)、(2, 3) ... (k-1, k)的分量的边。若存在,则半连通;反之,则不是半连通。算法时间复杂度为O(V+E)。
原文地址:https://www.cnblogs.com/mhpp/p/7420129.html