最小生成树
最小生成树的 Kruskal 算法,非常简单易懂
- 先按照边权从小到大排序。
- 依次将边的两个点加入到树中,加入前判断一下,这两个点是否已存在于树中(使用并查集 https://www.cnblogs.com/kingbuffalo/p/15380294.html)
- 并查集需要记录每个森林中有几个节点时,可以使用一个 cnts[NMAX] 以 节点ID为下标。初始为1 在合并时,cnts[fa_a] += cnts[fa_b] 即可
注:本身并查集算法就是可以用图的思想来思考的。
附:https://www.acwing.com/problem/content/348/ ac代码
#define NMAX 6006
#define ll long long
int fa[NMAX];
int cnts[NMAX];
struct Edge{
int x,y,z;
};
Edge edges[NMAX];
int getFa(int x){
return fa[x] == x ? x : fa[x]=getFa(fa[x]);
}
bool isSame(int a,int b){
return getFa(a) == getFa(b);
}
int main(){
int t;
int n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<=n;++i){
fa[i] = i;
cnts[i] = 1;
}
for(int i=0;i<n-1;++i){
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].z);
}
sort(edges,edges+n-1,[](const auto &a,const auto &b){
return a.z < b.z;
});
ll ret = 0;
for(int i=0;i<n-1;++i){
if ( !isSame(edges[i].x,edges[i].y) ){
int afa = getFa(edges[i].x);
int bfa = getFa(edges[i].y);
ret += (cnts[afa] * cnts[bfa] - 1) * (edges[i].z + 1);
fa[afa] = bfa;
cnts[bfa] += cnts[afa];
}
}
printf("%lld\n",ret);
}
return 0;
}