图论-最小生成树

今天听了CLRS的第二作者讲的课程,关于最小生成树的算法。

其实就是先模拟一下小样例(不是单纯模拟,而是发现其中的规律,要思考)

然后发现最优子结构-如果(u,v)是一条唯一连接两点的边,那么将原图拆分为两块(一块包含u,一块包含v),两图分别最优解+dist[u,v]就是原图的最优解了。

然后发现这样做会有很多很多的重叠子问题:把每次的(u,v)换一换顺序就一堆重叠子问题。于是就有动态规划的思路了……

别急!

这里还有一个性质:如果(u,v)在当前图中边权最小,则(u,v)必在此图的最小生成树中。

证明:

我们把此图(V,E)的点集合分为两个点集集合(A,B)且u∈A,v∈B,且A+B=V,A&B=∅;则在(V,E)的最小生成树中,必有一条边连接(跨越)A,B两个集合。

然而(u,v)必定比这条边优。所以(u,v)必在此图的最小生成树中。

贪心证明完毕!

下面讲一下求最小生成树的方法

方法1:Prim

根据上面性质,我们可以随便找一个原点,以这个点为原点扩展出最小生成树,然后做一下步骤的操作

1.将原图分为两个点集:一个代表已在最小生成树中的,另一个则是未知的

2.找出连接上述两个点集间权值最小的边,并把那个不属于最小生成树的点移到最小生成树中

3.把与(2)中的那个点相邻的所有不在最小生成树的点与最小生成树集合的距离更新(初始值为与原点的距离)

重复以上步骤最后所有点都会出现在最小生成树中。

时间复杂度:

1:直接暴力找出所有权值最小的边,为Θ(n^2);

2:用堆优化,对所有的dist插入一个堆中,记录一下终点(起点就是那个代表最小生成树的强连通分量),并支持减关键值操作(减关键值操作,并不用直接删去原来那个dist加上现在这个dist,因为后面那个dist肯定比前面那个优,而同样的点只能走一次)

令E=边的条数 

T(N)=O(E)*log(E)(每个点被更新了O(E)次-握手定理)=O(e*log v)

所以我们得出稠密图时暴力更优,稀疏时堆更优(Kruskal一样)

方法2:Kruskal

方法步骤:

感觉跟接近我们上面的证明

1.将所有边按权值排序

2.找到一条最小的边且连接两个不属于同意集合的点(初始时所有点都处于自己的集合内)

3.将这条边的两个顶点所属的集合合并,将这条边加入最小生成树中

2.3循环操作

时间复杂度:2的判断直接交给并查集,在路径压缩后为log*级别,忽略为常数

主要时间复杂度为排序O(ElgE)=O(Elg v)

适合稀疏图

原文地址:https://www.cnblogs.com/dancer16/p/6926113.html