Minimum Spanning Tree

一、Prim

Prim算法的思想是:

  1. 整个顶点集为(V),初始选一个起点(s),令集合(u={s}, v={})
  2. 在集合(u)与集合(V-u)中的点组成的边中,选一条权值最小的边(u_0v_0)加入MST,并且将(u_0)加入(u)
  3. 重复直到MST有(n-1)条边或(n)个顶点为止。
int adjMax[MAXN][MAXN];  //邻接矩阵

int n;   //顶点数目
int pos = 0, ans = 0;
bool visited[MAXN] = {0}, cost[MAXN];

void Prim()
{
	for (int i = 0; i < n; i++)
	{
		cost[i] = adjMax[0][i];  //集合u与集合V-u中的i点间距离最小值
		visited[i] = false;
	}

	visited[0] = true;   //已经在MST中

	for (int i = 1; i < n; i++)  //再找n-1个点
	{
	    //找到连接u和V-u的最小边并记录位置
		int tmp = INT_MAX;
		for (int j = 0; j < n; j++) 
		{
			if (visited[j] == false && cost[j] < tmp)
			{
				tmp = cost[j];
				pos = j;
			}
		}

		ans += tmp;
		visited[pos] = true;

        //加入某点后,V-u中的点j到u的距离可能变短,故更新cost[j]
		for (int j = 0; j < n; j++)
		{
			if (visited[j] == false && cost[j] > adjMax[pos][j])
			{
				cost[j] = adjMax[pos][j];
			}
		}
	}
}

性能:邻接矩阵表示不依赖于边数,复杂度(O(|V|^2)),适合边稠密的图。

二、Kruskal

该算法思想:将所有边的权值递增排序,如果加入某边后不构成回路,则将该边加入MST,直到MST中有(n-1)条边或(n)个顶点:

//用结构体存储边的信息
struct edge {
	int start, des;
	int val;
}edge[MAXN];

//用并查集判断有没有环
int UFSets[MAXN];
for (int i = 0; i < n; i++)
{
	UFSets[i] = -1;
}

//在S中查找并返回包含x的树的根
int find(int S[],int x)
{
	while (S[x] >= 0)
		x = S[x];
	return x;
}

void kruskal()
{
	for (int i = 0; i < m; i++)
	{
		int u = find(UFSets, edge[i].start);
		int v = find(UFSets, edge[i].des);

		if (u == v)  //edge[i]的两端点有相同的祖先,成环
			continue;

		ans += edge[i].val;
		UFSets[u] = v;  //合并两个并查集
		cnt++;

		if (cnt == n - 1)
			break;
	}
}

性能:复杂度(O(ElogE)),适合边稀疏、顶点多的图。

原文地址:https://www.cnblogs.com/EIMadrigal/p/12234280.html