算法导论22章基本的图算法 思考题总结 (转载)

22-1 (以广度优先搜索来对图的边进行分类)深度优先搜索将图中的边分类为树边、后向边、前向边和横向边。广度优先搜索也可以用来进行这种分类。具体来说,广度优先搜索将从源结点可以到达的边划分为同样的4种类型。

a.证明在对无向图进行的广度优先搜索中,下面的性质成立:

1.不存在后向边,也不存在前向边。

2.对于每条树边(u, v),我们有v.d = u.d + 1。

3.对于每条横向边(u, v),我么有v.d = u.d 或 v.d = u.d + 1。

b.证明在对有向图进行广度优先搜索时,下面的性质成立:

1.不存在前向边。

2.对于每条树边(u, v),我们有v.d = u.d + 1。

3.对于每条横向边(u, v),我们有v.d ≤ u.d + 1。

4.对于每条后向边(u, v),我们有0 ≤ v.d ≤ u.d。

ANSWER:

a:

1.假如(u, v)是前向边,则搜索结点v前必搜索u,则根据BFS,当搜索结点u以后必先搜索结点v,则(u, v)是树边;同理,若(u, v)是后向边,则(v, u)是树边;矛盾,所以不存在前向边和后向边。

2.对于每条树边(u, v)有v.π = u,切执行v.π = u的同时执行v.d = u.d + 1;在这之后u.d和v.d都不会改变,所以v.d = u.d + 1;得证。

3.由(u, v)为横向边可知,当搜索结点u时,v必须在队列中,否则(u, v)为树边,所以v.d ≤ u.d + 1。又由无向图横向边可知v.d ≥ u.d。所以u.d = v.d 或 u.d + 1 = v.d。

b:

1.假如(u, v)是前向边,则u.d < v.d,则搜索结点u时,结点v仍是白色,则(u, v)必是树边,矛盾;所以不存在前向边。

2.同a.2。

3.和a.3类似。

4.显然有v.d ≥ 0,又由后向边可知v.d ≤ u.d,得证。

22-2 (衔接点、桥和双连通分量)设G=(V,E)为一个连通无向图。图G的衔接点是指图G中的一个结点,删除该结点将导致图不连通。图G的桥是指图中的一条边,删除该条边,图就不再连通。图G的双连通分量是指一个最大的边集合,里面的任意两条边都处于同一条简单环路中。设Gπ=(V,Eπ)为图G的深度优先树。
(事实上这里的双连通分量是点-双连通分量,还有边-双连通分量)

问题:
a. 证明:Gπ的根结点是图G的衔接点当且仅当它在Gπ中至少有两个子结点。
证明:
因为在对无向图G进行DFS时,每条边要么是树边,要么是后向边,因此当根结点删除时,如果它有两个以上的的子结点,这些子结点是无法相互到达的,因此根结点是图G的衔接点

b. 设结点v为Gπ的一个非根结点。证明:v是G的衔接点当且仅当结点v有一个子结点s,且没有任何从结点s或任何s的后代结点指向v的真祖先的后向边。
证明:
考虑v的任意子结点s,如果s及其后代不能连回v的真祖先,那么显然,删除v之后,v的真祖先与s不再连通。
反过来,如果s或它的后代存在一条后向边连回v的真祖先,则即使删了v,以s为根的子树都可以通过这条后向边与v的真祖先连通。

c. 定义:
v.low=min{u.d
w.d:(u,w)是结点v的某个后代结点u的一条后向边}
(d为第一时间戳)
请说明如何在O(E)的时间内为所有结点v计算出v.low的值
解:
对图G进行DFS,设现在遍历到结点u,初始化u.low=u.d。
接下来寻找拓展结点,设该结点为v.
如果结点v未被访问过,则我们从结点v处DFS以求得v.low,用其更新u.low
否则如果v不是u的父亲,那么我们用v.d更新u.low

d. 说明如何在O(E)时间内计算出图G的所有衔接点
解:
c中基本说的差不多了,以下是细节:
进行DFS时同时维护father,确保不把儿子到父亲的路径当成后向边。
不能边DFS边输出,因为可能多次满足条件,所以只能做上标记。

e. 证明:图G的一条边是桥当且仅当该边不属于G中的任何简单环路。
证明:
若存在一个桥属于G中的一个简单环路,那么删除这条边后,该桥的两端结点根据定义仍然可以通过其他路径连通,矛盾;而如果一条边不属于任何简单环路,那么这条边的两端节点只能通过这条边连通(否则会出现新环路),因此删除这条边时图G不再连通,故此时这条边是桥。

f. 说明如何在O(E)时间内计算出图G所有桥。
解:
过程其实与求衔接点很相似,但要注意判定过程中有更改:
当u.d>v.low时(u,v)是桥(可以发现等号不能成立)

g. 证明:G的双连通分量是G的非桥边的一个划分
证明:
事实上就是让你证双连通分量中删去任意一个点都不影响连通性。
这是一个双连通图显然的性质,不详细证了。

h. 给出一个O(E)时间复杂度的算法来给图G的每条边e做出标记。这个标记是一个正整数e.bcc且满足e.bcc=e’.bcc当且仅当边e和边e’在同一个双连通分量中。
解:
从森林的每个根结点开始DFS,用类似于求衔接点的方法维护每个结点的low值,但为了保存bcc,我们还要建一个栈来保存没有访问过的边;如果遍历的边为后向边,我们就用反向边更新自己(要注意反向边不能指向父亲)

附:边-双连通分量可先做一次DFS标记出所有的桥,然后第二次DFS找出边-双连通分量,因为边-双连通分量是没有公共结点的,所以第二次DFS保证不经过桥即可。

22-3(欧拉回路)欧拉回路的算法来自1873年的Hierholzer,前提是假设图G存在欧拉回路,即有向图任意点的出度和入度相同。从任意一个起始点v开始遍历,直到再次到达点v,即寻找一个环,这会保证一定可以到达点v,因为遍历到任意一个点u,由于其出度和入度相同,故u一定存在一条出边,所以一定可以到达v。将此环定义为C,如果环C中存在某个点x,其有出边不在环中,则继续以此点x开始遍历寻找环C’,将环C、C’连接起来也是一个大环,如此往复,直到图G中所有的边均已经添加到环中。

数据结构如下:
(1) 使用循环链表CList存储当前已经发现的环;
(2) 使用一个链表L保存当前环中还有出边的点;
(3) 使用邻接表存储图G

使用如下的步骤可以确保算法的复杂度为O(E):
(1) 将图G中所有点入L,取L的第一个结点
(2) 直接取其邻接表的第一条边,如此循环往复直到再次到达点v构成环C,此过程中将L中无出边的点删除。环C与环CList合并,只要将CList中的点v使用环C代替即可。
(3) 如果链表L为空表示欧拉回路过程结束,否则取L的第一个结点,继续步骤(2)

22-4 (可到达性)设G = (V, E)为一个有向图,且每个结点u∈V都标有一个唯一的整数值标记L(u),L(u)的取值为集合{1,2,...,|V| }。对于每个结点u∈V,设R(u) = {v∈V:u→v}为从结点u可以到达的所有结点的集合。定义min(u)为R(u)中标记最小的结点,即min(u)为结点v,满足L(v) = min{L(w):w∈R(u)}。请给出一个时间复杂度为O(V + E)的算法来计算所有结点u∈V的min(u)。

ANSWER:按照结点L(u)顺序对每个结点查找该结点可到达的结点,并找出最小的L(v),即min(u);

对V个结点进行查找共计E条边,所以时间复杂度为O(V + E)。

时间: 2024-11-10 00:09:54

算法导论22章基本的图算法 思考题总结 (转载)的相关文章

算法导论22.4拓扑排序 练习总结 (转载)

22.4-1 给出算法 TOPOLOGICAL-SORT 运行于图 22-8 上时所生成的结点次序.这里的所有假设和练习 22.3-2 一样. ANSWER:   22.4-2 请给出一个线性时间的算法,算法的输入为一个有向无环图 G = (V, E) 以及两个结点 s 和 t,算法的输出是从结点 s 到结点 t 之间的简单路径的数量.例如,对于图 22-8 所示的有向无环图,从结点 p 到结点 v 一共有 4 条简单路径,分别是 pov.poryv.posryv 和 psryv.(本题仅要求计

算法导论22.3深度优先搜索 练习总结 (转载)

22.3-1 画一个 3*3 的网格,行和列的抬头分别标记为白色.灰色和黑色,对于每个表单元 (i, j),请指出对有向图进行深度优先搜索的过程中,是否可能存在一条边,链接一个颜色为 i 的结点和一个颜色为 j 的结点.对于每种可能的边,指明该种边的类型.另外,请针对无向图的深度优先搜索再制作一张这样的网格. ANSWER:   22.3-2 给出深度优先搜索算法在图 22-6 上的运行过程.假定深度优先搜索算法的第 5~7 行的 for 循环是以字母表顺序依次处理每个结点,假定每条邻接链表皆以

算法导论 第二章

2014-12-02 20:21:40 http://www.cnblogs.com/sungoshawk/p/3617652.html 上面链接指向算法导论第二章的预习博客,很值得一看,很详细. 插入算法: 1 #include <iostream> 2 3 using namespace std; 4 void insert_sort(int *datas, int length); 5 int main() 6 { 7 int a[10]={1,2,4,35,6,1,4,7,9,7};

算法导论 第一章

算法导论 第一章,为了让自己基本功更加的扎实,从今天起开始学习算法导论. 我以一位学长的博客为学习的参考资料,开始我的学习吧! 附上一句话: Having a solid base of algorithm knowledge and technique is one characteristic that separates the truly skilled programmers from the novices. 是否具有扎实的算法知识和技术基础,是区分真正熟练的程序员与新手的一项重要特

算法导论23章思考题(转载)

23-1次优最小生成树 a. 最小生成树唯一性证明: 已知当前构造的边集A是最小生成树的子集.令无向图G的一个切割是,显然该切割是尊重A的.已知跨越该切割的轻量级边对于A是安全的,又因为该无向图G的每条边的权值都不相同,所以对于当前A而言,安全边有且只有一条,即对于每个状态下的A,构造最小生成树的方式是唯一的.所以最小生成树是唯一的. 次优最小生成树不唯一性证明: 如上图:{(C, D), (A, D), (A, B)} 和 {(C, D), (A, C), (B, D)} 是两个次优最小生成树

算法导论第九章中位数和顺序统计量(选择问题)

本章如果要归结成一个问题的话,可以归结为选择问题,比如要从一堆数中选择最大的数,或最小的数,或第几小/大的数等, 这样的问题看似很简单,似乎没有什么可研究的必要,因为我们已经知道了排序算法,运用排序+索引的方式不就轻松搞定了?但细想,排序所带来的时间复杂度是不是让这个问题无形之中变得糟糕.那算法研究不就是要尽可能避免一个问题高复杂度地解决,让那些不敢肯定有无最优解的问题变得不再怀疑,这也是算法研究者所追求的一种极致哲学.既然排序让这个问题解决的性能无法确定,那我们就抛开排序,独立研究问题本身,看

算法导论第二章C++实现归并算法排序

归并算法排序的思想算法导论中讲的还算比较清楚. #include<iostream> using namespace std; void guibing(int *_array,int p,int q,int r); void merge_sort(int *_array,int p,int r); int main() { int a[8]={2,4,5,7,1,2,3,6}; int j1=0; int j2=7; merge_sort(a,j1,j2); int i=0; for(;i&

算法导论2-9章补充几道题

本篇博文意在对前几章中遗漏的,本人觉得有意思的习题当独拿出来练练手. 1.习题2-4,求逆序对,时间复杂度要求Θ(nlgn) 定义:对于一个有n个不同的数组A, 当i<j时,存在A[i]>A[j],则称对偶(i, j)为A的一个逆序对. 譬如:<2,3,8,6,1>有5个逆序对. 解题思路:归并排序的思想:逆序对的数量=左区间的逆序对+右区间的逆序对+合并的逆序对 代码如下: 1 #include <iostream> 2 #include <vector>

算法导论 第二章作业

//作业2. 1-2 template<class T> void insert(T* A, int  n) { for (int j = 1; j < n; ++j) { T key = A[j]; int i = j - 1; while (i >= 0 && key > A[i]) { A[i + 1] = A[i]; --i; } A[i + 1] = key; } } //2. 1-3 template<class T> void fin