求无向连通图的最小生成树算法.docx

上传人:牧羊曲112 文档编号:3612907 上传时间:2023-03-14 格式:DOCX 页数:5 大小:39.23KB
返回 下载 相关 举报
求无向连通图的最小生成树算法.docx_第1页
第1页 / 共5页
求无向连通图的最小生成树算法.docx_第2页
第2页 / 共5页
求无向连通图的最小生成树算法.docx_第3页
第3页 / 共5页
求无向连通图的最小生成树算法.docx_第4页
第4页 / 共5页
求无向连通图的最小生成树算法.docx_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《求无向连通图的最小生成树算法.docx》由会员分享,可在线阅读,更多相关《求无向连通图的最小生成树算法.docx(5页珍藏版)》请在三一办公上搜索。

1、求无向连通图的最小生成树算法求无向连通图的最小生成树算法Prim与Kruskal及相关优化 最小生成树是图论里很重要的部分。但是由于它属于图论所以NOIP基本不考,对于NOI又太基础,所以竞赛中出现的几率比较小,即使要考也不可能考裸的生成树算法= = 最小生成树就Prim和Kruskal两个算法,又没有多大的优化余地,所以学习起来还是很简单的。 一.Prim算法 1.算法思想 对于图G=(V,E),用Prim算法求最小生成树T=(S,TE)的流程如下 初始化:设S、TE为空集,任选节点K加入S。 选取一条权值最小的边,其中XS,且not (YS) 即,选取一条权值最小的、连接着S中一点与S外一

2、点的边。 将Y加入S中,边加入TE中 重复 直到V=S即所有G中的点都在S中,此时的T为G的最小生成树。 由此流程可见,Prim算法求最小生成树时任何时候的T都是一颗树。 2.实现 显然,Prim算法的主要运行时间花在过程的选边中。看起来复杂度是O(VE)=O(V3)不是么,效率也太低了吧 为了比较快速地选边,我们用两个数组lowcost、closest动态地维护每一个点到S的最短距离。在某一状态下,lowcosti表示所有与i相连且另一端点在S中的边中的权值最小值,closesti表示在S中且与i相连的点中与i之间距离最小的点。显然,lowcosti=w(i,closesti)。需要注意的是

3、两个数组记录的都是边而不是路径。若i没有边直接连向S,则lowcosti=。另外,若i已在S中,则lowcosti=0。 设出发点为x。初始时对于任意kV,closestk=x,lowcostk=w 每一次找出lowcost中不为0的最小值lowcosti,然后把i加入S,然后对于图中所有点k,若w(k,i)lowcostk,则把lowcostk赋为w(k,i),把closestk赋为i。 以上操作重复|V|-1次结束。由于每次加入S的点i都在当时取到了符合流程的边minlowcost,而lowcosti=w(i,closesti),所以此时的最小生成树的各边就是(i,closesti),iV

4、且not (i=x)。把i从1取到|V|,便得到最小生成树T的每条边。 Pascal程序: 不难看出,以上算法包含一个二重循环,算法复杂度为O,与图的稠密度无关。 3.使用堆优化 如果我们把要取的边作为一个最小优先级队列,用堆来选取边与调整,则算法可以得到优化。 对于上面代码绿色部分,转换成堆后就是一个建立一个有V个节点的小根堆的过程,复杂度为O;对于红色部分,就是取堆顶元素并删除、维护;对于橙色部分,对于for循环我们可以用一个数组edgei记录与i节点相连的所有边,这样我们就把for循环的复杂度变成了与E相关。显然,图中的每条边仅在其两顶点进入最小生成树时被访问一次,也就是每条边被访问2次

5、,因此橙色部分的执行次数总共是2E次而与外面的while无关。里面的lowcost修改时需要维护堆,复杂度为O。因此,算法的总复杂度为O=O。具体程序见本文最下方。 对于|E|接近|V|的稀疏图,算法复杂度接近O显然比O的算法优秀很多。然而对于E接近N2的稠密图,算法复杂度接近O反而不如平方算法。因此,使用堆优化的Prim算法适用于稀疏图,而不优化的Prim算法适用于稠密图。不过O实际上不比O(V2)慢多少,而现在的题目大多是稀疏图,所以这个算法在总体上是优于朴素Prim算法的。 顺便一提,如果用斐波那契堆来做的话,时间复杂度可以进一步优化为O。但事实上这样做的代码长度会到令人发指的地步,所以

6、是一种只存在于论文的算法。应付一般的竞赛用堆优化的Prim就可以应付所有数据了。 二.Kruskal算法 1.算法思想 设最小生成树为T=,初始时设TE为空集。将G中所有边按权值排序,从小到大选取边。若当前选取的边加入TE后不会使TE出现环,则将边加入TE,否则舍弃之。当TE中有n-1条边时,算法结束。此时T=就会形成环。因此,若一条边连接两个连通分量就不会形成环,反之则会形成环。初始时每一个点就是一个连通分量,当加入时,判断i与j是否属于不同连通分量。如果是的话,在加入边后把i与j所在的连通分量合并。重复以上操作,就可以保证不会产生环。 2.实现 显然,Kruskal的难点在于判断、合并连通

7、分量。Pascal语言中已有集合类型可以实现这一操作,不过竞赛中set是一个极其危险的类型。此处只用到查询、合并两个操作,是一个很明显的并查集模型,每一个连通分量就是并查集里的一个集合,通过并查集的算法即可实现算法。 3.时间复杂度分析 对E条边排序的复杂度为O;E次并查集的查找、合并的复杂度也约为O,因此算法的复杂度为O。又由于|E|的取值范围为=,所以log|E|的范围是。因此O可以写作O。为了方便与Prim算法复杂度的比较,一般来说把Kruskal的复杂度表述为O 三、Prim、Kruskal、Prim+Heap算法效率实测 评测环境:WindowsXP,FreePascal2.40,P

8、entium Dual-Core CPU T43002.10GHz,2G内存 通过上图可以看出: 1.Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。 2.Prim+Heap在任何时候都有令人满意的的时间复杂度,但是代价是空间消耗极大。 3.时间复杂度并不能反映出一个算法的实际优劣。 竞赛所给的题大多数是稀疏图,所以尽可能地使用Prim+Heap吧,在稀疏图中这是无敌的。如果一定要在朴素Prim和Kruskal里选一个的话那就用Kruskal吧。当然Prim的代码比较简单,对付水题用Prim也无所谓,只要不是极稀疏图两者相差不大。 最后附上Pascal写的Prim+Heap程序: 此处为了优化时间复杂度,把邻接表和邻接矩阵都用到了,否则对邻接矩阵的初始化都要n2的时间,比整个ElogV的算法还慢。这也是堆优化的Prim容易超空间的原因= = 当然,邻接矩阵实际上根本用不上,把邻接表的基类型改成record记录端点和权值就省掉了n2的空间,但是实际上是我太懒了

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号