算是最后几个完成这一章节学习的了,有不少思想和技巧都很好,须要好好学习算法
主要涉及两个算法: \(Prim\) 算法和 \(Kruskal\) 算法学习
感谢lsp为本文订正作出的贡献!spa
先跑一遍 \(Dij\) 求出 \(D_i\),再遍历每一个点,统计有几种修建方案
而后根据乘法原理,求出全部方案数便可
(感受和最小生成树没半毛钱关系是吧排序
Codeget
要求将整个图的节点通电,因此发电站必定要有,并要结合电网来达到最小花费。
想象一下,电从哪来?不能凭空产出,只能从外边接(感性理解/cy)
因此能够建一个虚点(总电源),发电站只有链接总电源才能通电。class
因此这个题就转化成,另设一个虚点将全部节点链接,而后建一个总的最小生成树的板子题了原理
Code遍历
由于给出的数据必定是最小生成树,因此直接开始建树
在建树过程当中,每一次合并当成两个联通块相连技巧
由于要求构成彻底图,设两个相连的联通快分别为 \(cnt_i\) 和 \(cnt_j\) 那么两个联通块之间最多能连 \(cnt_i \times cnt_j - 1\) 条边(由于最小生成树的边已经统计过一次了因此要减一)
要求最小生成树惟一,因此这些边的边权是对应的 \(e[i].w + 1\),统计后两个联通快记得和成一个联通块im
考虑建树边统计答案这种作法的正确性:其中的任何一条边都不可能做为最小生成树的一条边,由于有比他更优的边已经链接了两个联通块(类比 \(Kruskal\) 的贪心原理,可能这道题就是为了理解这个算法的原理而存在的)
本质同严格次小生成树,只是数据范围略有不一样
牛奶运输不是严格次小,不过用严格次小的代码居然也能过/jk
大致思路:建出最小生成树 \(\to\) 用 \(LCA\) 预处理最大值的次大值 \(\to\) 遍历全部不在最小生成树上的边,记录统计后的答案哪一个更小 \(\to\) 切掉此题
一开始考虑先用白边生成树,再用黑边生成树。若是这样作的话,生成的树可能不是联通的。换一种说法就是有可能有不是很优的白边也能够在生成树上。
一个很奇妙的思路:
二分一个值,让白边减掉这个权值,而后跑最小生成树,当所用数量恰好等于白边而且权值最小时就是答案。注意最后的答案要加上减去的权值
正确性:经过改变白边的权值来改变白边在全部边中的位置,减得越多白边在排序中越靠前,在最小生成树中的数量也越多,反之越少。所以具备单调性,能够二分出最恰当的那个要减得权值
考虑一棵最小生成树中,若是有其余建树方式,为了保证权值和不变,那么新加的边与减掉的边边权必定是相同的
那么咱们统计出全部边权相同的边,并将他们分组放在一块儿。根据最小生成树的贪心思想,先连小边再连大边。每连一种权值的边,爆搜有多少种连边方式。最后根据乘法原理统计答案便可
我在想一个正确性:有没有一种状况,能把两条边同时替换为一大一小的两条边也能使其成为一棵最小生成树
证实:一开始就是从小到大连边,因此小的边的状况已经统计上了,这种状况在一次建树后就不可能出现(题目中说无重边和子环也是一个前提