先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。
时间复杂度为为O(e^2), 使用并查集优化后复杂度为 O(eloge),与网中的边数有关,适用于求边稀疏的网的最小生成树。
这个算法大概就分为以下步骤:
1、对图中的所有边按照权值大小进行排序
2、依次选择边,若与现有的边构成回路,则放弃这个边,选次小的边继续判断。若没有构成回路,则加入。
3、直到这个集合包含所有节点,即成为一颗生成树为止。
模版如下。find是并查集。u,v数组用来存每一条边的两个端点,w数组存边的权值。p[x]代表x的父节点,r用来存放排序后的边。
int u[maxn],v[maxn],w[maxn],p[maxn],r[maxn];
int cmp(const int i,int j)
{
return w[i]<w[j];
}
int find(int x)
{
return p[x]==x ? x:p[x]=find(p[x]);
}
int kruskal(int m)
{
int ans=0;
for(int i=0;i<m;i++) p[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];
int x=find(u[e]);
int y=find(v[e]);
if(x!=y)
{
ans+=w[e];
p[x]=y;
}
}
return ans;
}