引出最小生成树,是提到电子线路设计时,要把数个元件的引脚连接在一起,使其电位相同。使n个引脚互相连通,可以使用n-1条连接线,每条连接线连接两个引脚。寻求连接线最少的方案,是最小生成树的应用。将电子线路引脚接线连接问题模型化求解一个无向带权连通图的顶点互联最小代价。

一个无向带权连通图G=(V,E),其中V是引脚集合(顶点),E是每个引脚之间可能互联的集合(边)。图中每一条边(u,v)∈E,都有一个权值w=(u,v)表示连接u和v的代价(引脚间接线数目)。

从这样一个图中找出一个无回路的子集T⊆E,这个子集T连接了所有顶点,且其边权值之和最小。

T无回路且连接所有顶点,是一个树,成为生成树,权值最小,即是最小生成树。求解图G的T子集的问题就是最小生成树问题。如何从一个图中生成一颗最小生成树,主要有Kruskal和Prim两个算法,时间性能都是O(ElgV)。其中Prim算法通过采用斐波那契堆可将运行时间减少到O(E+VlogV),适用于|V|远小于|E|的图求解最小生成树。

不得不说的,两个算法的思想核心是贪心算法。在算法的每一步中,都必须在几种可能性中选择一种,动态规划是都选择并求解最优子解最后组合成最优解;而贪心算法则是选择可能性中最佳的一种来求解最优子解。一般来说,贪心算法这种策略不能保证找到全局最优解,但在最小生成树问题上,通过贪心策略可以获得最小权值的生成树是可证的。

通用最小生成树算法:

假设已知一个无向连通图G=(V,E),其权值函数w:E->R,目的是找出图G的最小生成树。

通用最小生成树算法采用贪心策略,在每一个步骤都形成最小生成树的一条边。算法维护一个边集合A,保持循环不变式:

在每一次循环迭代之前,A是某个最小生成树的一个子集。

在算法的每一步中,确定一条边(u,v),是的将它加入集合A后,仍然不违反这个循环不变式,即AU{(u,v)}仍然是某一个最小生成树的子集,这样的边(u,v)为A的安全边。安全边加入子集A后,A仍然保持是某一个最小生成树的子集。

这是贪心算法思想,每一步寻找可能解中最优。那问题就是,怎么寻找安全边,确保加入A后使A仍然是最小生成树的子集。

算法导论中给出一个识别安全边的规则,适用于无向图。先给出这个规则的定理。

设图G=(V,E)是一个无向连通图,并且在E上定义了一个具有实数值的加权函数w。设A是E的一个子集,它包含于G的某个最小生成树中。设割(S,V-S)是G的任意一个不妨害A的割,且边(u,v)是通过割(S,V-S)的一条轻边,则边(u,v)对集合A来说是安全的。

这个定理中关键有三点,第一:将图分为两个子图S和V-S,即为割(S,V-S);第二:割(S,V-S)的边(u,v)是轻边,就是连接子图S和V-S所有边中最小权值的一条;第三:已经在子集A的边不能是连接割的边,称之为不妨害A的割;

算法导论中证明识别安全边的规则就不具体展开,主要是构造一个通用图,不失为普通的情况来证明。通俗地理解就是:将图分割成两个子图,两个子图间的联系的边中最小权值的就是安全边,前提是这些边不能是集合A中的。这里按归纳法证明下:

假设图G=(V,E)是一个无向连通图,

割(1,V-1),那1个顶点和V-1个顶点两个子图之间最小权值的边就是安全边了,A集合中有1个顶点,无边;

割(2,V-2),引入第二个顶点时,2和V-2割之间的边显然不会妨害A集合,找出两个割之间的最小权值也容易,加入安全边,集合A有一条边,就是(1,2);

如此类推,n个顶点加入时,割(n,V-n)中n个顶点之间的构成子图就是集合A的轻边,就是最小生成树。通用算法之上改良的有Kruskal和Prim算法。

Kruskal算法将集合A(最小生成树的顶点集和边集)是一个森林,加入集合A中的安全边总是途中连接两个不同连通分支的最小权边。而Prim算法则将集合A形成单颗树,加入集合A的安全边总是连接树与一个不在树中的顶点的最小权边。

实际,二者思想是一致,只不过通过不同的数据结构来实现,时间性能分析中还涉及到增长极为缓慢的函数。Prim算法应用二叉最小堆和斐波那契堆保存最小优先队列Q也有不同的性能效果。

Kruskal算法描述如下:

1)图G=(V,E)中的每个顶点都是一棵树,这样初始有V颗树,按照E的权值大小排序边集。初始化最小生成树,即集合A为空集;

2)按顺序找出权限的边集中的安全边,如果该边的两个顶点属于不同树,那么可以合并两棵树,并把边加入到集合A中;

3)直到所有的顶点都已在集合A中,其边权值最小。

核心思想就是贪心算法的,找出森林中权值的最小的边,然后合并该边联系的两棵树。或者从因到果的过程来看,要找出最小生成树,我就把所有边按顺序排序,依次将最小权值的边纳入集合A中。

Prim算法描述如下:

1)集合A是一颗正在成长的单棵树,树从任意顶点开始,逐渐生成直到覆盖所有顶点;

2)生成过程是将连接树A和G-A中最小权值的边加入A;

通俗地说,就是从图中的任意一个顶点出发,找到该顶点所有的边,把最小权值的边放入集合A中即可。实现该算法,要借助一个变量:最下优先级队列Q。Q保存所有顶点中与顶点相连的边中的最小权值。Q二叉最小堆实现,时间性能和Krusal算法一样,但若使用斐波那契堆可以改善。

两个算法基本都是将最小权值的边找出来,然后将安全边的顶点加入集合A中,从而逐步构成一棵正在成长的最小生成树。

这里给出平摊分析中提到的增长极快函数及其增长极慢的逆函数,有助于理解在时间性能分析中引入增长极慢函数的意义。

增长极快的函数:

10的80次方已经是可观察到的宇宙中估计的原子数量。

有点像2的64次方的故事,数学的魔力在于此,简单这样的一个函数设计,只要k=4就已经大到无边,大到目今我们所认知宇宙的数量极限。

对应增长极慢的函数,就是该函数的逆函数。对整数j≥0,定义函数Ak(j)的逆函数为:

a(j)=min{k: Ak(1)≥j}

a(j)是的函数Ak(1)至少为j的最低级别k。根据增长极快函数Ak(1)的值,可知:

a(j)=0,当0≤j≤2

a(j)=1,当j=3

a(j)=2,当4≤j≤7

a(j)=3,当8≤j≤2047

a(j)=4,当2048≤j≤A4(1)

可见如此,在实际应用中的数字一般都是只有a(j)≤4,是一个增长极为缓慢的函数,变量超级无敌大,我依旧小于4。让人不禁想起阿基米德的豪言壮语:给我一个支点,我就能支起地球。宇宙之极大又或者是极小,未可知啊。

算法导论之图的最小生成树相关推荐

  1. Java实现算法导论中图的广度优先搜索(BFS)和深度优先搜索(DFS)

    对算法导论中图的广度优先搜索(BFS)和深度优先搜索(DFS)用Java实现其中的伪代码算法,案例也采用算法导论中的图. import java.util.ArrayList; import java ...

  2. 算法导论之图的基本算法

    图是一种数据结构,有关图的算法是计算机科学中基础性的算法.这个论述恰如其分. 图的基本算法包括图的表示方法和图的搜索方法.图的搜索技术是图算法领域的核心,有序地沿着图的边访问所有顶点,可以发现图的结构 ...

  3. 算法导论-上课笔记10:最小生成树

    文章目录 0 前言 1 最小生成树 2 Kruskal算法 3 Prim算法 0 前言 在电路设计中,常常需要将多个组件的针脚连接在一起.要连接n个针脚,可以使用n-1根连线,每根连线连接两个针脚,则 ...

  4. 图的最小生成树算法(图解+代码)| 学不会来看我系列

    文章目录 最小生成树 Prim算法 1.介绍 2.图解步骤 3.算法分析 算法问题 解决方案 4.代码实现 Kruskal算法 1.介绍 2.图解 3.算法分析 算法问题 解决方案 4.代码实现 最小 ...

  5. C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)

    1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...

  6. 图的最小生成树和最短路径算法思路总结(Prim,Kruskal,Dijkstra,Floyd)

    带权无向图->最小生成树算法->Prim算法: 思路: 首先,我们先设置两个集合,U_{}:一个用来放最小生成树的顶点,T_{}:一个用来放最小生成树的边.选取最开始的点V_0,将V_0放 ...

  7. 克鲁斯卡尔算法(Kruskal Algorithm)——图的最小生成树

    听骚话讲作者 [手动滑稽] 其实早就该写这篇博客啦. 图的最小生成树 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.最小生成树可以 ...

  8. 图的最小生成树-Kruskal算法

    问题引入 [问题描述] 编写程序,利用带权无向图的邻接矩阵存储,实现图的最小生成树Kruskal算法. [输入形式] 输入图的顶点序列及图的边的情况.如样例所示.边的输入以输入-1,-1,-1作为结束 ...

  9. 算法:通过克鲁斯卡尔(Kruskal)算法,求出图的最小生成树

    之前我给大家分享过用普利姆(Prim)算法来求出图的最小生成树(点我去看看),今天我再给大家分享一个也是求图的最小生成树的克鲁斯卡尔(Kruskal)算法 克鲁斯卡尔(Kruskal)算法,就相当于先 ...

最新文章

  1. 靠谱的N95消毒方法终于来了:放你家电饭锅里,干烧丨伊利诺伊香槟分校出品...
  2. 启明云端分享|ESP32-C3模块入门应用
  3. LeetCode 143 重排链表-中等
  4. git reflog and checkout
  5. mysql 异步复制建立过程_mysql生产环境高可用---基于GTID异步复制项目实施
  6. gson json转map_Java 中几种常用 JSON 库性能比较
  7. eclipse怎么显示代码行数
  8. AngularJS Eclipse——新手入门【翻译+整理】
  9. 面向对象第二单元总结
  10. docker配置 nacos_Docker下配置nacos
  11. C语言函数指针和指针函数的定义和调用
  12. iOS判断 英文 数字 汉字等
  13. 【全开源+免费更新】doodoo.js快速入门教程 1
  14. 敏捷项目管理的前世今生及应用-Part 2(之3355)
  15. kubectl常用命令大全详解
  16. 佳能Canon PIXMA MX715 打印机驱动
  17. 微软一个罕为人知的无敌命令
  18. Consumer接口和Supplier接口
  19. ARCGIS地图导出问题
  20. 【解禁】钉钉直播回放下载

热门文章

  1. wps怎么投递简历发到boss直聘_BOSS直聘情色招聘:洗脑传销广告漫天飞,还陷虚假招聘...
  2. java静态分派_Java基础——重载、静态分派与动态分派
  3. mysql按照datetime精确查询_MySQL datetime字段查询按小时:分钟排序
  4. Win2008 r2 iis7/iis7.5系统下HTTP重定向(301重定向)图文方法
  5. 消息队列如何保证顺序性?
  6. nginx限制ip,只允许域名访问
  7. iOS之Block总结以及内存管理
  8. 【Unity3D基础教程】给初学者看的Unity教程(四):通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider2D...
  9. JavaScript学习笔记——JS中的变量复制、参数传递和作用域链
  10. Java Map hashCode深究