作者:zykBlog

链接:https://www.cnblogs.com/zykBlog

来源:https://www.cnblogs.com/zykBlog

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

AcWing 346. 走廊泼水节

题目思路
将一个最小生成树的图,添加一些边,使得成为一个完全图,并且生成的完全图的最小生成树还是原树
算法分析
构建最小生成树的Kruskal算法

  1. 首先将所有的边按照从小到大的顺序排序
  2. 对于一条边(x,y,w),如果x和y在不在一个连通块中,就说明他们之间没有边相连那么我们相连之后,现在这两个点,各自所在的连通块(集合),都拥有了一个最短边,也就是(x,y,w)

最小生成树已经确定了,那么原来两个连通块的其他点怎么办?
假设Sx表示为x之前所在的连通块,那么Sy表示y之前所在的连通块。
由于我们不能破坏最小生成树,所以我们原来这两个连通块必须具有如下性质:假设点A属于Sx这个集合,点B属于Sy这个集合,那么A与B之间的距离,必须大于之前的w否者就会破坏之前的最小生成树,所以说

ABw+1


假如Sxp个元素,然后Syq个元素,那么将SxSy连通块中所有的点相连,就会增加:

p×q1

每条边的最小长度为w+1
所以就会得出

(w+1)×(p×q)

实现代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 6010;

struct Edge
{
    int a, b, w;
    bool operator < (const Edge & t)
    {
        return w < t.w;
    }
}e[N];

int n;
int T;
int p[N], s[N];

int find(int x)
{
    if(x != p[x]) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    cin >> T;
    while(T --)
    {
        cin >> n;
        for(int i = 0;i < n - 1;i++)
        {
            cin >> e[i].a >> e[i].b >> e[i].w;
        }
        
        sort(e, e + n - 1);
        
        for(int i = 1;i <= n;i++) p[i] = i, s[i] = 1;
        int res = 0;
        for(int i = 0;i < n - 1;i++)
        {
            int a = find(e[i].a), b = find(e[i].b), w = e[i].w;
            if(a != b)
            {
                p[a] = b;
                res += (s[b] * s[a] - 1) * (w + 1);
                s[b] += s[a];
            }
        }
        cout << res << endl;
    }
    return 0;
}
posted @   0xcf  阅读(36)  评论(0)    收藏  举报
编辑推荐:
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· Android编译时动态插入代码原理与实践
· 解锁.NET 9性能优化黑科技:从内存管理到Web性能的最全指南
· 通过一个DEMO理解MCP(模型上下文协议)的生命周期
阅读排行:
· 工良出品 | 长文讲解 MCP 和案例实战
· 多年后再做Web开发,AI帮大忙
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· centos停服,迁移centos7.3系统到新搭建的openEuler
· 上周热点回顾(4.14-4.20)

作者:zykBlog

链接:https://www.cnblogs.com/zykBlog

来源:https://www.cnblogs.com/zykBlog

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

点击右上角即可分享
微信分享提示