构造完全图(G)解题报告


题目描述

对于完全图 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; }

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM