最小生成树之克鲁斯卡尔算法(Kruskal)

最小生成树的概念:给出n个点,选择n-1条边把n个点连接起来,使得n个点在一个连通分量里,并且要使这些边的边权总和最小。

克鲁斯卡尔算法是”加边法“,采用了贪心的策略,把任意两点之间的边权排序,然后依次选择权值最小的边加入到生成树中,直到选出n-1条边算法结束。在选取的过程中如果出现这条边连接的2个点在一个连通分量里,就舍弃这条边,继续下一次选取,因为如果选择了这条边,生成树中就会出现环。

算法的关键在于连通分量的查询与合并:需要知道任意两个点是否在一个连通分量里,还需要合并两个连通分量。这里我们采用的是并查集来维护。

并查集这里不给出过多的介绍,下面贴出2个函数的代码,分别表示寻找连通块中的代表元素并且压缩路径,和合并并查集。

int Find(int x)
{
    return p[x]==x?x:p[x]=Find(p[x]);
}////p[x]保存x的父节点,如果x就是代表元素,p[x]=x.
void join(int x,int y)//////合并并查集
{
    int px=Find(x),py=Find(y);
    if(Find(x)!=Find(y))
        px=p[py];////这里的赋值顺序不要写反
}

这样,克鲁斯卡尔算法的代码就不难给出了

struct stu
{
    int u,v,w;
}
bool cmp(stu s1,stu s2)
{return s1.w<s2.w;
}
int Kruskal()
{
int value=0;
for(int i=0;i<n;i++)p[i]=i;
sort(node,node+m,cmp);
for(int i=0; i<m&&t<n-1; i++)
        {
            int p=Find(node[i].u);
            int q=Find(node[i].v);
            if(p!=q)////这说明加入这条边不会形成环
            {
                value=value+node[i].w;
               p[q]=p;
                t++;
            }
      return value;
        }



猜你喜欢

转载自blog.csdn.net/zero___zero/article/details/80698529