题目描述
对于完全图 G,若有且仅有一棵最小生成树为 T,则称完全图 G 是树 T 扩展出的。
给你一棵树 T,找出 T 能扩展出的边权和最小的完全图 G。
输入格式
第一行 N 表示树 T 的点数;
接下来 N−1 行三个整数 Si,Ti,Dii,Ti,Di;描述一条边(Si,TiS_i, T_iSi,Ti)权值为 DiD_iDi;
保证输入数据构成一棵树。
输出格式
输出仅一个数,表示最小的完全图 G 的边权和。
样例
样例输入
4
1 2 1
1 3 1
1 4 2
样例输出
12
样例说明
添加 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; }