《算法导论》笔记(15) 最小生成树 部分习题

来源:互联网 发布:成功的网络促销 编辑:程序博客网 时间:2024/05/23 17:19

习题23.1-11 给定图G和一棵最小生成树T,假设减少了位于T之外的某条边的权重。因为T内的边,是连接所有结点的权重最小的,那么首先将T外的减少权重的边(u, v)加入T,然后在u, v中寻找所有的路径,去掉路径中权重最大的边。

习题23.2-3 使用斐波那契堆实现的Prim算法与使用二叉堆比较。因为斐波那契堆实现优先队列,使Prim算法的运行时间为O(E+VlgV),而二叉堆实现优先队列的Prim算法运行时间为O(VlgV+ElgV),前者更小。同时,稠密图使用斐波那契堆实现Prim算法更有优势。因为E越大,需要更新堆中元素次数越多。

习题23.2-4 边权重为1~|V|整数的图的Kruskal算法。边排序用计数排序,时间为O(E),有O(V)次make_set与O(E)次find_set和union,总时间为O(E+α(V)*(E+V))。如果边权重为1~W,则取决于W与|V|中最大值。

习题23.2-5 边权重为1~|V|整数的图的Prim算法。若最小优先队列用斐波那契堆,总运行时间为O(E+VlgV)。前一项代表执行更新堆中元素值的时间,后一项代表出堆时间。但若W<lgV,最小优先队列用一个1~W的计数桶来实现。每次出列操作的时间为O(W),则总时间为O(E+V*W)。

习题23.2-6 图中所有边权重均匀分布在[0,1)内的Prim算法与Kruskal算法比较。边的排序用桶排序,时间为O(E),对于kruskal算法,有O(E)次find_set和union,O(V)次make_set。运行时间为O(E+α(V)*(E+V)),而用了斐波那契堆作最小优先队列的Prim算法,总时间为O(E+VlgV)。可见,Kruskal算法更快。

习题23.2-7 图的最小生成树已经被计算出来,加入新结点与边,更新最小生成树的时间。可以将与新结点相连的结点从最小生成树中删除,然后只考虑这些结点的边,用Prim或者Kruskal算法重新生成最小生成树。

思考题23-1 次优最小生成树,相对于最小生成树只有一条边不同,即去掉最小生成树上一条边,加入另一条原本没有的边。假设去掉的边为E(u,v),加入的边为E'(j,k),E'-E是增加的权重,那么可能有多种u、v、j、k的选择,得到相同的E'-E。

将全部的点分为两个连通集,很显然,连接两个连通集的所有边中,最小权重边是最小生成树的边,而次大权重的边是次优最小生成树的边。假设已有一最小生成树,然后检查每条边,将此边删除,分最小生成树为两个连通集,并找到次大的边使连通集合并,得到新的生成树的权重。同样的方法操作所有边,选择最小权重的生成树即为次优生成树。显然,次优生成树可能有不止一种。取决于删除的边与加入的边权重之差。

计算max[u, v],可以按照BFS搜索的方式,搜索出全部的路径,然后统计出路径中最大的边。时间O(V^2)。

计算次优最小生成树的算法,可以先计算最小生成树,然后在原图中测试每一条不在最小生成树的边(u,v),寻找最小生成树中的max(u,v),令d= w(u, v) - max(u, v),得到所有的d然后寻找最小值。对应的(u, v)替换最小生成树中的max(u, v),为次优最小生成树。

思考题23-2 稀疏图的最小生成树。每一次收缩的过程,实质就是选择连接两个连通集的最小边过程。整个过程相当于分治法,先分成两个一组的连通集,然后这些小连通集两两合并,每次合并,都选择最小权重的边,直到所有连通集合并为一个。足以保证最终得到的就是最小生成树。

MST-Reduce实现的关键是set的结构。对所有边的遍历,都要查找两个端点所在的set,但每趟reduce过程合并一次set,后面全部是查找操作,那么只需要对每个元素标记一次根元素就可以了。运行时间是先生成set为O(E),遍历边是O(E),所以总运行时间是O(E)。若运行k趟reduce过程,每次迭代后,结点数量变为原来的一半V/2,边数量变为E-V/2,则k趟运行总时间是O(k*E- (V/2+ V/4...+V/2^k) )。,后项的极限为2V,故总时间为O(k*E)。

因为最后运行Prim时的复杂度为O( E‘ + V'lgV' ),其中E'= E-V/2 -V/4 -...-V/(2^k)为最后的边数,V'=V/(2^k)为最后的结点数,则总复杂度为O( k*E +E’ + V'lgV' )。问题等价于取k*E+ V/(2^k)*(lgV- k)的最小值。K应当取小于lgV但是大于1的整数。求导并化简,忽略增长缓慢的项,E-VlgV*k/2^k=0,得k/2^k = E/VlgV。有2^(k-lgk)=VlgV/E,k=O(lg(VlgV/E))。总运行时间为O(kE+V/2^k*lgV)= O(kE)= O(E*lg(VlgV/E)),又因为E、V相差不超过平方量级,可等视之,总运行时间为O(E*lglgV)。

由2^(k-lgk)=VlgV/E,E=VlgV/(k-lgk),故运行带预处理的Prim算法的条件是K有正整数解,E<VlgV.

思考题23-3 瓶颈生成树。首先,不可能有瓶颈生成树的T值小于最小生成树。假设瓶颈生成树去掉最小生成树的一条边而加入另一条边,则必然超过了最小生成树的最大边权重。否则两连通分量之间引入了非最小边。

线性时间算法判断瓶颈生成树的T值。判断T值是否大于b,可DFS从任意结点开始遍历图,途中若有超过b的边则删除,终止时若不能遍历所有结点,图不连通,说明瓶颈生成树的T值不超过b。

将全部边按照权重大小分为2个部分,权重小的子集按照DFS遍历。若不连通,证明瓶颈生成树的T值小于子集最大权重边。则将此子集再分为两半并以相同方法DFS遍历。若连通,则收缩至一个点,与另外一半子集合并重新查找。重复多次直到全部收缩为1个点并找到T值。时间为O(E)+ O(E/2)+ O(E/4)+......,极限为O(2E)= O(E)

思考题23-4 第三种最小生成树算法。

Maybe_MST_A(),正确。任意两个连通集,先删掉的是权重大的边,最后保留的是权重最小的边。

Maybe_MST_B(),不对。加入的边没有环路,只能保证生成树,但是不能保证边都是最小的权重,因为顺序是任意的。

Maybe_MST_C(),正确。加入的边没有环路,则任意点只有一条边与外界相连,每次操作最多构成一个新的连通子集。每次形成环路后删除最大权重的边,保证了任意两个连通子集之间的路径都是最小的。故可以得到最小生成树。


0 0
原创粉丝点击