首页 > 代码库 > ACM:最小生成树,kruskal && prim,并查集

ACM:最小生成树,kruskal && prim,并查集

题目:

输入顶点数目,边的数目,输入每条边的两个顶点编号还有每条边的权值,求最小生成树,输出最小生成树的权值。。


注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。

kruskal----归并边;prim----归并点


方法一:kruskal,克鲁斯卡尔,并查集实现。

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 1000;
int n, m;
int u[MAXN], v[MAXN], w[MAXN], r[MAXN], fa[MAXN];
int ans = 0;

//假设第i条边的两个端点序号和权值分别保存在u[i], v[i]和w[i]中。
//而排序后第i小的边的序号保存在r[i]中。

bool cmp(int i, int j) {   //间接排序!
	return w[i] < w[j];
}

int find(int x) {
	return x == fa[x] ? x : fa[x] = find(fa[x]);  //把遍历过的节点都改成树根的儿子,提高后续查找的速度。
}

int kruskal() {
	int ans = 0;
	for(int i = 0; i < n; ++i) fa[i] = i;   //初始化并查集,让每一个点自成一个连通分量。
	for(int i = 0; i < m; ++i) r[i] = i;    //初始化边序号。
	sort(r, r+m, cmp);     //间接排序!
	for(int i = 0; i < m; ++i) {
		int e = r[i];   //e代表边的序号!
		int x = find(u[e]), y = find(v[e]);   //找出这条边的两个顶点所在的集合的代表元
		if(x != y) {     //如果这两个点不在同一个连通分量
			ans += w[e];  //把这条边加入到MST中
			fa[x] = y;    //合并两个集合!
		}
	}
	return ans;
}

int main() {
	cin >> n >> m;
	for(int i = 0; i < m; ++i) {
		cin >> u[i] >> v[i] >> w[i];
	}
	cout << kruskal() << endl;
	return 0;
}


方法二:prim,普里姆,实现。