(」・ω・)」うー!(/・ω・)/にゃー!
——潜行吧奈亚子

最小生成树

最小生成树

一般来说,最小生成树的题目大多与图的连通性最小边权和有关,因此就很容易想到一种十分容易实现的算法:

先按照边权排序,再从最小的边开始枚举,若联通且不产生回路,就加入到生成树中,直到加到\(N-1\)条边为止(即已经成为了树且不形成回路)

那问题来了,代码怎么写,不难想到可以使用并查集,把所有的顶点加入并查集,枚举到就查询是否有相同的祖先即可。

代码如下:

#include<iostream>
using namespace std;
struct edge {
	int u;//点
	int v;//点
	int w;//权值
};
struct edge e[10];//为了方便排序,使用了结构体来存储这些边
int n, m;
int f[7] = { 0 };//并查集用
void quicksort(int left, int right) {
	int i, j;
	struct edge t;
	if (left > right) {
		return;
	}
	i = left, j = right;
	while (i != j) {
		//先从右边找
		while (e[i].w >= e[left].w && i < j) {
			j--;
		}
		//再从左边找
		while (e[i].w <= e[left].w && i < j) {
			i++;
		}
		//交换
		if (i < j) {
			t = e[i];
			e[i] = e[j];
			e[j] = t;
		}
	}
	//最后把基准数归位,把left和i互换
	t = e[left];
	e[left] = e[i];
	e[i] = t;
	quicksort(left, i - 1);//处理左边
	quicksort(i + 1, right);//处理右边
	return;
}
void init(int n) {
	for (int i = 1; i <= n; i++) {
		f[i] = i;
	}
}
int getf(int v) {
	if (f[v] == v) {
		return v;
	}
	else {
		//路径压缩
		f[v] = getf(f[v]);
		return f[v];
	}
}
int merge(int v, int u) {
	int t1, t2;
	t1 = getf(v), t2 = getf(u);
	if (t1 != t2) {
		f[t2] = t1;
		return 1;
	}
	return 0;
}
int main(){
	int i, sum = 0, count = 0;
	cin >> n >> m;
	//n为顶点数,m为边数
	for (int i = 1; i <= m; i++) {
		cin >> e[i].u >> e[i].v >> e[i].w;
	}
	quicksort(1, m);
	init(n);
	for (int i = 1; i <= m; i++) {
		if (merge(e[i].u, e[i].v)) {
			count++;
			sum += e[i].w;
		}
		if (count == n - 1) {
			break;
		}
	}
	cout << sum;
	return 0;
}
posted @ 2021-12-25 22:09  GalaxyOier  阅读(27)  评论(0)    收藏  举报