acwing346走廊泼水节——最小生成树转化成完全图

本文探讨了在给定一棵N个节点的树时,如何通过增加边将其转化为完全图,同时保持其最小生成树不变,目标是最小化新增边的权值总和。文章介绍了一种基于Kruskal算法的解决方案,详细解释了算法步骤和实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.acwing.com/problem/content/description/348/

给定一棵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

做法:利用kruskal算法,每次将两个连通块合并时(两个连通块时完全图),算出将这两个连通块合并时构成完全图的最小代价。
维护每个集合的数量num[];
即:ans += (num[f[x]]num[f[y]]-1)(w+1); num[f[x]] = num[f[x]] + num[f[y]];

ac代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 6005;
const int M = 6005;

struct Node{
    int a,b,w;
    bool operator < (const Node & t) const {
        return w<t.w;
    }
}g[M];
int f[N],num[N];
int n,m,T;

int find(int x){
    if(x != f[x])
        f[x] = find(f[x]);
    return f[x];
}

//将y合并到集合x中
void merge(int x,int y){
    x = find(x);y = find(y);f[y] = x;
}
int ans ;
void kru(){
    int i,j;
    for(i = 1;i<=n;i++) f[i] = i;
    for(i = 1;i<=n;i++) num[i] = 1;//初始化每个集合的数量
    sort(g+1,g+1+m);
    for(i = 1;i<=m;i++){
        int x = g[i].a,y = g[i].b,w = g[i].w;
        if(find(x) == find(y))  continue;
        //两个集合合并
        ans += (num[f[x]]*num[f[y]]-1)*(w+1);
        num[f[x]] = num[f[x]] + num[f[y]];
        merge(x,y);
    }
}


int main(){
    int i,j;
    cin>>T;
    while(T--){
        cin>>n;
        ans = 0;
        m = n-1;
        for(i = 1;i<=m;i++){
            cin>>g[i].a>>g[i].b>>g[i].w;
        }
        kru();
        cout<<ans<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值