最小生成树
Posted eimadrigal
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树相关的知识,希望对你有一定的参考价值。
一、Prim
Prim算法的思想是:
- 整个顶点集为(V),初始选一个起点(s),令集合(u={s}, v={});
- 在集合(u)与集合(V-u)中的点组成的边中,选一条权值最小的边(u_0v_0)加入MST,并且将(u_0)加入(u);
- 重复直到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)),适合边稀疏、顶点多的图。
以上是关于最小生成树的主要内容,如果未能解决你的问题,请参考以下文章