最小生成树

最小生成树的 Kruskal 算法,非常简单易懂

  1. 先按照边权从小到大排序。
  2. 依次将边的两个点加入到树中,加入前判断一下,这两个点是否已存在于树中(使用并查集 https://www.cnblogs.com/kingbuffalo/p/15380294.html)
  3. 并查集需要记录每个森林中有几个节点时,可以使用一个 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;
}
posted @ 2022-06-13 16:07  传说中的水牛  阅读(17)  评论(0编辑  收藏  举报