样例输入
样例输出
样例说明
添加 D(2,3)=2,D(3,4)=3,D(2,4)=3D(2, 3)=2, D(3, 4)=3, D(2, 4)=3D(2,3)=2,D(3,4)=3,D(2,4)=3 即可。
题目链接:https://loj.ac/problem/10067
解题思路:首先完全图是指每两个点之间都有连边的图,题目是要求一个边权和最小的完全图,
题目给出的是一个最小生成树,我们可以从边入手,把每条边所连的左右两个点分别看做一个集合,
左边集合和右边集合所要连的边数是(cnt[i]*cnt[j]-1),我们要连的边权是多大?不能比当前的边还小,
那么就不满足有且仅有一棵最小生成树T,所以边权就为(当前边的边权+1),我们可以贪心的去解决,
把边从小到大排序,并查集一下就行了,当然还得加上原始边的边权。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long int
using namespace std;
struct T{
ll u,v,w;
}t[100005];
ll ans,n,cnt[100005],fa[100005];
ll find(ll x){
if(fa[x]!=x)
return fa[x]=find(fa[x]);
else
return fa[x];
}
bool cmp(T a,T b){return a.w<b.w;}
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n-1;i++)
scanf("%lld%lld%lld",&t[i].u,&t[i].v,&t[i].w),ans+=t[i].w;
for(ll i=1;i<=n;i++){
fa[i]=i;cnt[i]=1;
}
sort(t+1,t+n,cmp);
for(ll i=1;i<=n-1;i++){
ll r1=find(t[i].u);
ll r2=find(t[i].v);
if(r1!=r2){
ans+=(cnt[r1]*cnt[r2]-1)*(t[i].w+1);
fa[r2]=r1;
cnt[r1]+=cnt[r2];
}
}
printf("%lld",ans);
return 0;
}