算法竞赛进阶指南 走廊泼水节

给定一棵 N 个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树。

求增加的边的权值总和最小是多少。

注意: 树中的所有边权均为整数,且新加的所有边权也必须为整数。

输入格式

第一行包含整数 t,表示共有 t 组测试数据。

对于每组测试数据,第一行包含整数 N。

接下来 N−1 行,每行三个整数 X,Y,Z,表示 X 节点与 Y 节点之间存在一条边,长度为 Z。

输出格式

每组数据输出一个整数,表示权值总和最小值。

每个结果占一行。

数据范围

1≤N≤6000
1≤Z≤100

输入样例:

2
3
1 2 2
1 3 3
4
1 2 3
2 3 4
3 4 5 

输出样例:

4
17 

先介绍什么是完全图:

完全图:对于图中的任意一点a,点a除了自己外对于图中所有点均有一条边相连 

解题思路:

我们先假设a, b两个边分别在两个完全图中 a, b的权值为w

 此时我们要将左边和右边的完全图合并,假设左边完全图和右边完全图的点的数量分别为n, m要将两个完全图合并为一个完全图即对于左边完全图中的任意一点都要向右边完全图中任意一点连一条边,因此连接的边的总数为n * m;

1:首先我们先按边的大小从小到大排序,假设枚举到点a, b时,他们的权重为w.因为边是从小到大排序的所以当前枚举的边即为两个完全图中权值最大的边。

2:我们加边的权值应该加多少:

{

        1:若加的边的权值小于w,则原a, b, w就不是最小生成树,不可行

        2:若加的边的权值等于w,  则有两个一样的最小生成数,但题意要求需要满足唯一的最               小生成数,因此不可行

        3:若加的权值大于w,由于权值从小到大排序,所以两个完全图的权值全都小于w,因               此加上一个大于w的数不影响最后结果,又因为求的是权值的最小值,所以我们把每               条边加上w + 1即可;

}

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 6010;

int n;
int p[N];//记录的是N的祖宗节点
int cnt[N];//记录的是节点数量
struct Edge
{
    int a, b, w;
    bool operator < (const Edge &W) const
    {
        return w < W.w;
    }
}edges[N];

int find(int x)//并查集模板
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ )//初始化
        {
            p[i] = i;
            cnt[i] = 1;
        }
        
        for (int i = 0; i < n - 1; i ++ )
        {
            int a, b, w;
            scanf("%d %d %d", &a, &b, &w);
            edges[i] = {a, b, w};
        }
        
        sort(edges, edges + n - 1);//按权值从小到大排序
        
        int res = 0;
        for (int i = 0; i < n - 1; i ++ )
        {
            int a = find(edges[i].a), b = find(edges[i].b), w = edges[i].w;
            
            if (a != b)
            {
                p[a] = b;
                res += (cnt[a] * cnt[b] - 1) * (w + 1);//对于a, b所在的两个完全图中
                //总共要连接cnt[a] * cnt[b]条边,但是要除去a -> b本身的边(最小生成树定义)
                cnt[b] += cnt[a];//新的完全图b的节点个数
            }
        }
        
        cout << res << endl;
    }
    
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥也不会hh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值