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 }

 

posted @ 2022-07-18 09:17  YHXo  阅读(16)  评论(0编辑  收藏  举报