求次小生成树的做法
1)先求出最小生成树,依次枚举删最小生成树上的边,再做一遍kruskal算法,得到的结果取min。O(mlongm + nm)
一个结论:最小生成树一定和次小生成树只差一条边,为什么?
反证法:假如两者相差两条边,分别是a和b x和y 那么b>= a, y >= x 那么对于第二条边来说我们把之前的边替换上去得到的权值一定不会 :假如两者相差两条边,分别是a和b x和y 那么b>= a, y >= x 那么对于第二条边来说我们把之前的边替换上去得到的权值一定不会 差。该结果可以推论到相差n条边上。即两者只能也只会差一条边(防止有人抬杠,就算两者相等我替换过去不可以吗?)
证明解法一正确性:
因为只会相差一条边,因此枚举最小生成树的每一条边删去再做kruskal一定会找到 最终答案。
注意:该做法只能保证求解到的非严格次小生成树是正确的,而无法保证严格次小生成树的正确性,为什么?
答:按照上述做法,假如最小生成树中存在在ad边,但是ab有重边x条,其中和ab相等的有x-1条,比x大的有1条,且这道题的正解是把比x大的那一条替掉ab,但是由于这么多重边存在即使再次做kruskal算法也得不到正解,因此这种解法只能用求非严格次小生成树。即使保证不存在重边也不一定对,这点读者可自行证明。
2)先求最小生成树,再求出最小生成树上的每个点到另一个点的经过的最大距离dmax[x][y], 和严格小于最大距离的次大距离dmin[x][y],然后分别枚举非树边,比较sum - dist[x][y] + wi; 即可。O(mlogm + n^2);
if(w[i] > dmax[x][y])res = min(res, sum + w[i] - dmax[x][y]; // 如果大于当前的最大距离,用最大距离更新
else if(dmin[x][y] != -1) res = min(res, sum + w[i] - dmin[x][y]);//如果次大距离存在用次大距离更新
正确性证明:因为只会相差一条边,那么依次枚举非树边,把它加上去一定会形成环,那么就要从最小生成树中选择一条边进行替换,因为保证权值是比最小生成树大的最小值,min(sum -dist[x][y] + w)最小,由于w 和sum 是确定的那么只能保证dist[x][y]最小即可,因此找到数中最大的点即可。