【问题描述】 对于完全图G,若有且仅有一棵最小生成树为T,则称完全图G是树T的扩展出的。给你一 棵树T,找出T能扩展出的边权和最小的完全图G。
【文件输入】 第一行N表示树T的点数。 接下来N-1行:Si,Ti,Di;描述一条边(Si,Ti)权值为 Di。 保证输入数据构成一棵树。
【文件输出】 一个数,表示最小的图G的边权和。
【样例输入】 4 1 2 1 1 3 1 1 4 2
【样例输出】 12
【样例说明】 添加D(2,3)=2,D(3,4)=3,D(2,4)=3即可。
【数据范围】 对于20%的数据,N<=10 对于50%的数据,N<=1000 对于100%的数据,N<=100000,1<=Di<=100000
首先,作为一名OIer,看到最小生成树,脑海中一定会浮现Prim算法和Kruskal算法。
我们可以从Prim算法生成最小生成树的过程中获得灵感:
对于一个图的最小生成树中的每一条边 E<s,t>,都有:E在与s相连的所有边中权值最小,且E在与t相连的所有边中权值最小。
这个结论同样适用于本题的完全图G。
由于本题给出的是一个最小生成树T,所以我们可以知道,T中的每一条边都是一条割边。
去掉任意一条树T中的边,这个树一定会变成两个联通块,令其为A、B。要将T扩展为完全图G,那么显然 A中的每个点都需要与B中的所有点相连。
由之前推出的结论可得,A中新发出的连边的权值一定是大于(若等于则存在多种最小生成树解,不合题意)发出点在树上的相接边的权值的。
再一看数据量,单独枚举肯定不行。由联通块可以联想到并查集,发现可行。
对于一条最小生成树上的边E<A,B>,可以看做E连接了A,B两个联通块,那么要将A、B两块连接为一个完全图需要加的边数就是 cnt[A]*cnt[B]-1,其中cnt表示联通块中的结点个数。
由结论可得,这些边的权值一定是大于E的权值的,要使其最小,那么这些边的权值都是 E的权值+1
那么合并A、B两个联通块的花费就是 (边E.权+1)*(cnt[A]*cnt[B]-1)。ans在每次合并联通块时加上花费即可求解。
另外一点,因为要求的是最小的完全图,所以有一个贪心策略:先把树上的边按照权值从小到大排序,然后枚举即可。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<string> 6 using namespace std; 7 template<class T> inline void read(T &_a){ 8 bool f=0;int _ch=getchar();_a=0; 9 while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();} 10 while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();} 11 if(f)_a=-_a; 12 } 13 14 const int maxn=100001; 15 struct edge 16 { 17 int from,to,next; long long dis; 18 bool operator < (const edge x) const {return dis<x.dis;} 19 }w[maxn]; 20 int n,fa[maxn]; 21 long long ans,cnt[maxn]; 22 23 int find(int u) 24 { 25 return fa[u]==u?u:fa[u]=find(fa[u]); 26 } 27 28 int main() 29 { 30 freopen("tree.in","r",stdin); 31 freopen("tree.out","w",stdout); 32 read(n); 33 for (register int i=1;i<n;++i) read(w[i].from),read(w[i].to),read(w[i].dis),ans+=w[i].dis; 34 for (register int i=1;i<=n;++i) fa[i]=i,cnt[i]=1; 35 sort(w+1,w+n); 36 for (register int i=1;i<n;++i) 37 { 38 int a1=find(w[i].from); 39 int a2=find(w[i].to); 40 ans+=(w[i].dis+1)*(cnt[a1]*cnt[a2]-1); 41 fa[a1]=a2; 42 cnt[a2]+=cnt[a1]; 43 } 44 printf("%lld",ans); 45 return 0; 46 }