--引入超级源点解决,点权问题:
把点权记为这个点到超级源点的边权,这样问题不就转换为了最小生成树问题吗?
根据分析我们可以转换题意为:
--找一个最小的 d 值,把所有权值大于d的边删去后,得到的连通块数量不超过k
那么我们将会得到这样一张图
so 要求ans我们只需要枚举连通块的数量递减的情况求ans即可
so我们会想到使用Kruskal算法去实现连通块递减,把初始化连通块赋值为cnt=n个(最大--每个点就是一个连通块),当cnt== k时的 前一个e[i].w就是ans了,即当d==e[i].w的时候我们刚好可以得到k个连通块
int cnt = n; //表示连通块个数-- 初始化为n -最大为每个点表示一个连通块
double res = 0;
for (int i = 0; i < m; ++i) {
if (cnt <= k)break;
int a = find(e[i].a), b = find(e[i].b);
if (a != b) {
p[a] = b;
res = e[i].w;
cnt--;
}
}
printf("%.2lf\n", res);
我们再来进一步解释我们存的res为什么存的是还有k+1个连通块的时候的dist
因为我们图解的意思也是当d==res 的时候我们刚好可以分为k份
而k份恰好是有第k+1个连通块是的e[i].w分出来的,这样写就符合图意了
这题乍一看比较简单,但是深究我们就会发现有意思的地方
本体要求次短生成树
1.唉,有的小伙伴(我)一下子就来灵感了--那我就用Kruskal求最小生成树的时候到第n-1条边跳过(不把边所在连通块连通),加第n条边(这个边和第n-1条边在同一个 连通块)
--乍一看好像还挺对的,是吧,但是仔细想想有不想漏掉了什么,我们这样只是从小到大枚举了所有边,但是最后一条边所在连通块我们不能保证这个连通块的第二条边长度-第一条边长度大于之前连通块的情况
2.so,考虑到每个连通块,那么小伙伴又激动了
那么不就是先求一颗最小生成树,在依次替换即可嘛
思路:
1)求(建立)最小生成树,同时标记每条边是树边,还是非树边;
2)预处理两点之间的边权最大值
3——枚举所有非树边,求min(sum+w-dist[a][b]),
满足w>dist[a][b]--严格次小
画图证明:
如图,(最小生成树)图中x到y的最长边是4 ,我们能拿到生成树外随便x到y的一条边,都能替换掉4这条边,不影响连通性,当这条边w> 4时,最小生成树的边权和会变大--次大边
so 为什么要求最大边dist[x][y],因为 res=min(res,sum-dist[x][y]+w)-的值越大res就越小--次小用w> dist[x][y]和min 来限制
替换如下
诶,想想看是不是很正确呢?哈哈,一开始我也是这么想的
但是 no,大no特no!!!
提出假设:有没有一种可能,当x到y的最大距离恰好dist[x][y]==w呢,有这种可能的嘛
但是这种情况不代表第二大的数不能考虑啊,即当最大的数恰好是==w的时候我们第二大的数是<w的,可以考虑更新答案
(xx的奇思怪想构想--那次大值也是==最大值==x的时候呢,我们是不是得顺延下去啊
no!你个笨比!我们这里求的最大值和次大值都是严格最大,严格次大,不能相等)
so最终通牒:
要分别求出最大值和次大值,在最大值不能更新的时候使用次大值更新我们的答案即可
逻辑代码如下:
//dfs求最大值和次大值:
得解,无敌xx好累啊,真遇到对手啦~~~555
4.AcWing 1148. 秘密的牛奶运输 - AcWing
题意:给你一课最小生成树,要你在这棵最小生成树中加入一些边使得这个图变成完全图,并且新的图中的最小生成树还是原来那颗,则,加入新边之和最小是多少?
思路:本体有边权为整数限制,因为我们的最小生成树地位不可撼动,so我们加入的边权要>w,这样就不回更新了,那么大于w的第一个整数是不是w+1呢,接下来统计一共加多少条边即可
一共加多少边:用Kruskal算法每次两个区间合并的时候我们就加入p*q-1条边(p,q分别为两区间大小,-1表示连接两个连通块中的那条边是最小生成树的树边不是新边不需要考虑)