2023年8月1日发(作者:)
最⼩⽣成树之Kruskal算法 给定⼀个⽆向图,如果它任意两个顶点都联通并且是⼀棵树,那么我们就称之为⽣成树(Spanning Tree)。如果是带权值的⽆向图,那么权值之和最⼩的⽣成树,我们就称之为最⼩⽣成树(MST, Minimum Spanning Tree)。 我们由最⼩⽣成树的定义,可以延伸出⼀个修建道路的问题:把⽆向图的每个顶点看作村庄,计划修建道路使得可以在所有村庄之间通⾏。把每个村庄之间修建道路的费⽤看作权值,那么我们就可以得到⼀个求解修建道路的最⼩费⽤的问题。 常见求解最⼩⽣成树的算法有Kruskal算法和Prim算法。由于篇幅问题再此对于Prim算法,就不多做解释了。现在我们看看Kruskal算法,是怎么来求解最⼩⽣成树的问题。1、Kruskal算法描述 Kruskal算法是基于贪⼼的思想得到的。⾸先我们把所有的边按照权值先从⼩到⼤排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同⼀集合,那么就将它们合并,直到所有的点都属于同⼀个集合为⽌。⾄于怎么合并到⼀个集合,那么这⾥我们就可以⽤到⼀个⼯具——-并查集(不知道的同学请移步:)。换⽽⾔之,Kruskal算法就是基于并查集的贪⼼算法。2、Kruskal算法流程 对于图G(V,E),以下是算法描述:输⼊: 图G输出: 图G的最⼩⽣成树具体流程:(1)将图G看做⼀个森林,每个顶点为⼀棵独⽴的树(2)将所有的边加⼊集合S,即⼀开始S = E(3)从S中拿出⼀条最短的边(u,v),如果(u,v)不在同⼀棵树内,则连接u,v合并这两棵树,同时将(u,v)加⼊⽣成树的边集E'(4)重复(3)直到所有点属于同⼀棵树,边集E'就是⼀棵最⼩⽣成树 我们⽤现在来模拟⼀下Kruskal算法,下⾯给出⼀个⽆向图B,我们使⽤Kruskal来找⽆向图B的最⼩⽣成树。
⾸先,我们将所有的边都进⾏从⼩到⼤的排序。排序之后根据贪⼼准则,我们选取最⼩边(A,D)。我们发现顶点A,D不在⼀棵树上,所以合并顶点A,D所在的树,并将边(A,D)加⼊边集E‘。 我们接着在剩下的边中查找权值最⼩的边,于是我们找到的(C,E)。我们可以发现,顶点C,E仍然不在⼀棵树上,所以我们合并顶点C,E所在的树,并将边(C,E)加⼊边集E' 不断重复上述的过程,于是我们就找到了⽆向图B的最⼩⽣成树,如下图所⽰:3、Kruskal算法的时间复杂度 Kruskal算法每次要从都要从剩余的边中选取⼀个最⼩的边。通常我们要先对边按权值从⼩到⼤排序,这⼀步的时间复杂度为为O(|Elog|E|)。Kruskal算法的实现通常使⽤并查集,来快速判断两个顶点是否属于同⼀个集合。最坏的情况可能要枚举完所有的边,此时要循环|E|次,所以这⼀步的时间复杂度为O(|E|α(V)),其中α为Ackermann函数,其增长⾮常慢,我们可以视为常数。所以Kruskal算法的时间复杂度为O(|Elog|E|)。4、实战演练 我们现在已经基本了解了Kruskal算法,让我们来⼀道题⽬练练⼿:。这是⼀道⾮常基本的最⼩⽣成树的应⽤,所以我就不做详细说明了,这⾥仅附上代码以供参考:#include
2023年8月1日发(作者:)
最⼩⽣成树之Kruskal算法 给定⼀个⽆向图,如果它任意两个顶点都联通并且是⼀棵树,那么我们就称之为⽣成树(Spanning Tree)。如果是带权值的⽆向图,那么权值之和最⼩的⽣成树,我们就称之为最⼩⽣成树(MST, Minimum Spanning Tree)。 我们由最⼩⽣成树的定义,可以延伸出⼀个修建道路的问题:把⽆向图的每个顶点看作村庄,计划修建道路使得可以在所有村庄之间通⾏。把每个村庄之间修建道路的费⽤看作权值,那么我们就可以得到⼀个求解修建道路的最⼩费⽤的问题。 常见求解最⼩⽣成树的算法有Kruskal算法和Prim算法。由于篇幅问题再此对于Prim算法,就不多做解释了。现在我们看看Kruskal算法,是怎么来求解最⼩⽣成树的问题。1、Kruskal算法描述 Kruskal算法是基于贪⼼的思想得到的。⾸先我们把所有的边按照权值先从⼩到⼤排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同⼀集合,那么就将它们合并,直到所有的点都属于同⼀个集合为⽌。⾄于怎么合并到⼀个集合,那么这⾥我们就可以⽤到⼀个⼯具——-并查集(不知道的同学请移步:)。换⽽⾔之,Kruskal算法就是基于并查集的贪⼼算法。2、Kruskal算法流程 对于图G(V,E),以下是算法描述:输⼊: 图G输出: 图G的最⼩⽣成树具体流程:(1)将图G看做⼀个森林,每个顶点为⼀棵独⽴的树(2)将所有的边加⼊集合S,即⼀开始S = E(3)从S中拿出⼀条最短的边(u,v),如果(u,v)不在同⼀棵树内,则连接u,v合并这两棵树,同时将(u,v)加⼊⽣成树的边集E'(4)重复(3)直到所有点属于同⼀棵树,边集E'就是⼀棵最⼩⽣成树 我们⽤现在来模拟⼀下Kruskal算法,下⾯给出⼀个⽆向图B,我们使⽤Kruskal来找⽆向图B的最⼩⽣成树。
⾸先,我们将所有的边都进⾏从⼩到⼤的排序。排序之后根据贪⼼准则,我们选取最⼩边(A,D)。我们发现顶点A,D不在⼀棵树上,所以合并顶点A,D所在的树,并将边(A,D)加⼊边集E‘。 我们接着在剩下的边中查找权值最⼩的边,于是我们找到的(C,E)。我们可以发现,顶点C,E仍然不在⼀棵树上,所以我们合并顶点C,E所在的树,并将边(C,E)加⼊边集E' 不断重复上述的过程,于是我们就找到了⽆向图B的最⼩⽣成树,如下图所⽰:3、Kruskal算法的时间复杂度 Kruskal算法每次要从都要从剩余的边中选取⼀个最⼩的边。通常我们要先对边按权值从⼩到⼤排序,这⼀步的时间复杂度为为O(|Elog|E|)。Kruskal算法的实现通常使⽤并查集,来快速判断两个顶点是否属于同⼀个集合。最坏的情况可能要枚举完所有的边,此时要循环|E|次,所以这⼀步的时间复杂度为O(|E|α(V)),其中α为Ackermann函数,其增长⾮常慢,我们可以视为常数。所以Kruskal算法的时间复杂度为O(|Elog|E|)。4、实战演练 我们现在已经基本了解了Kruskal算法,让我们来⼀道题⽬练练⼿:。这是⼀道⾮常基本的最⼩⽣成树的应⽤,所以我就不做详细说明了,这⾥仅附上代码以供参考:#include
发布评论