伪代码:
把所有边排序,记第i小的边为e[i](1<=i<m)
初始化MST为空
初始化联通分量,让每个点自成一个独立的联通分量
for(int i = 0;i < m;i++)
if(e[i].u和e[i].v不在同一个联通分量)
{
把边e[i]加入MST
合并e[i].u和e[i].v的联通分量
}
首先把所有边按照权值排序,找到最小的权值所在的边,用这些点构造联通图可以保证图的权值最小。然后依次搜索,每次都找到下一个最小的点,如果这些点已经包含在联通图里,说明我们如果现在把它们放进去,图的权值会大于我们之前已经构建的图,不符合题意。所以只添加没有包含的点。如此扫描下去直到把所有点加进去,因为每个点加进去的都是最小权值,所以图的权值最小,也叫最小生成树(MST)
下一个关键问题是合并:合并的最简单表示方式是用并查集。用树表示集合。把点x的父节点保存在p[x]中(如果没有父节点,p[x]=x)。所以找出节点所在树的递归程序是:
int find(int x){p[x] == x?x:p = find(p[x]);}返回x所在的树根。
代码:int cmp(const int i,const int j){return w[i] < w[j];}//间接排序函数
int find(int x){return p[x] == x?x:p = find(p[x]);}//查找结点的树根
int Kurskal()
{
int ans = 0;
for(int i = 0;i < n;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;
}