给定一棵 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算法的思想反推即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=6e3+10;
struct node{
int u,v,w;
};
vector<node>an;
vector<int> tem;
int cnt[N],fa[N];
int t,n;
bool cmp(node x1,node x2)
{
return x1.w<x2.w;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<n;i++)
{
int x,y,z;
cin>>x>>y>>z;
an.push_back({x,y,z});
}
sort(an.begin(),an.end(),cmp);
long long ans=0;
fill(cnt+1,cnt+n+1,1);
for(int i=0;i<n-1;i++)
{
int u=find(an[i].u), v=find(an[i].v), w=an[i].w;
if(u==v)continue;
ans+=(long long)(cnt[u]*cnt[v]-1)*(w+1);
fa[v]=u;
cnt[u]+=cnt[v];
}
cout<<ans<<endl;
an.clear();
}
return 0;
}