最小生成树及最大生成树(算法及正确性简单证明)
最小生成树
kruskal
kruskal算法步骤:
- 将所有边按权值从小到大排序
- 将边按序加入最小生成树
a. 如果该边连接的两点已经属于一个集合,则舍弃该边
b. 如果该边连接的两点不属于一个集合,则加入该边,并将所连两点用并查集合并 - 当加入n-1条边后得到的就是该图的最小生成树
这么做时间复杂度为\(O(M\log M)\),M为边的总数,这是给所有边按权排序的时间复杂度,之后并查集的时间复杂度我不太清楚,大概在\(O(N\log N)\)。
这里用到了贪心思想,也许你会怀疑:为什么这么做是对的?
证明应该分为两部分:首先证能连成树,再证这种连法是权值最小的。
首先第一部分十分显然,一个n个点的连通图一定能连成一棵树。
主要来看第二部分:
如果当前边连接的两点不在一个集合里,按照kruskal算法应该加入该边,我们假设舍弃会有更好的结果,最后得到一棵不含该边的最小生成树,我们此时再把该边加入,一定会出现一个环,在该环上不可能所有边比这条边小,如果所有边比这条边小,那么会与我们在加入该边时这两个点时不连通情况矛盾,那么这个环上一定有边的权值是大于等于该边的,如果我们用这条边把权值大于等于该边的边替换,得到的生成树权值不会大于原生成树,所以能加入时加入这一策略是对的。由此证明了贪心的正确性。
prim
prim算法步骤我懒得写了,提一嘴时间复杂度是\(O(N\log N)\),接着我简单证明一下正确性吧
prim算法也是运用贪心的思想。要证明prim算法是对的,关键是要证,对于一个集合,离集合最近的边一定是在最小生成树上。
算了,懒得证了,哪天有时间再补吧
最大生成树
顾名思义,最大生成树就是权值最大的生成树。
我们很容易想到:按照最小生成树的做法反过来做不就好了?
但这样对吗?
按照以上最小生成树贪心正确性的证明,我认为这样是对的。
当然,有一种更保险的做法,把所有边边权改为\(X-W\),\(X\)是我们赋的一个很大的数,再跑一遍最小生成树,得到的结果是\(X*(N-1)-\sum W\),因为\(X*(N-1)\)是一个常数,所以减去该常数取反得到的一定是最小生成树权值和。