acwing346 走廊泼水节 (最小生成树)
完全图就是每两个点都有直接相连的边。
模拟Kruskal算法的过程,每选择一条边加入时,他两端端点在同一个集合中就跳过,否则考虑合并两个集合,合并时需要增加的每条边的权值至少是edge[i]+1,这才使得最小生成树不会改变,记录每个集合大小统计要增加的边数,累加答案。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 struct rec{ 7 int x,y,z; 8 }edge[6010]; 9 int fa[6010],s[6010],n,T; 10 long long ans; 11 12 bool operator < (rec a,rec b){ 13 return a.z<b.z; 14 } 15 16 int get(int x){ 17 return fa[x]==x?x:fa[x]=get(fa[x]); 18 } 19 20 int main(){ 21 cin>>T; 22 while(T--){ 23 cin>>n; 24 for(int i=1;i<n;i++) 25 scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z); 26 sort(edge+1,edge+n); 27 for(int i=1;i<=n;i++) 28 fa[i]=i,s[i]=1; 29 ans=0; 30 for(int i=1;i<n;i++){ 31 int x=get(edge[i].x); 32 int y=get(edge[i].y); 33 if(x==y) continue; 34 ans+=(long long)(edge[i].z+1)*(s[x]*s[y]-1); 35 fa[x]=y; 36 s[y]+=s[x];//合并两个集合 37 } 38 printf("%d\n",ans); 39 } 40 return 0; 41 }