克鲁斯卡尔求最小生成树

Posted l1l1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了克鲁斯卡尔求最小生成树相关的知识,希望对你有一定的参考价值。

处理何种问题:求解最小生成树,适合点多边少的无向图。(以证明,放心用)

 

性能:时间复杂度为O(e*loge),e为边的个数。

 

原理:贪心策略

 

实现步骤

<1>设一个有n个顶点的联通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T={V,空},图中的每一个顶点自成一个连通分量。

<2>在E中选择一条具有最小权值的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点属于同一个连通分量,将此边舍去(此后永不选用这条边),重新选择一条权值最小的边。

<3>如此重复下去,直至选了(n-1)条有效边,或者所有的顶点都在同一连通分量上为止。

 

备注:在此之前,本人对于网上给出的对于克鲁斯卡尔的证明并不理解,只觉得这种贪心策略有Bug,这次换一个角度去理解这个算法:<1>一个孤立的点V要想连入最后的那个生成树中,只需要找到在边的中找连接V,且权值最小的那条边即可,则可证明,权值最小的那条边必然在最后的最小生成树中;<2>对于已经连线的两个孤立点,可看作一个点,他们共享互相边的性质。<3>一颗生成树有且仅有n-1条边。根据以上三点,即可推出克鲁斯卡尔的正确性。只是在实现方式上有些难以理解。

 

输入样例解释

4 6//顶点的个数,边的个数

1 2 1//一条边的两个顶点和该边上的权值

1 3 4

1 4 1

2 3 3

2 4 2

3 4 5

输出样例解释

5//该无向图的最小生成树

代码

#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;

const int MaxN=510;///最大顶点的数
const int MaxM=251000;///最大边数
int F[MaxN];///并查集

struct Edge
{
    int u,v,w;
};
Edge edge[MaxM];///储存边的信信息,包括起点/终点/权值

int tal;///边数,加边前赋值为0

void addedge(int u,int v,int w)
{
    edge[tal].u=u;
    edge[tal].v=v;
    edge[tal].w=w;
    ++tal;
}

bool cmp(Edge a,Edge b)///排序函数,边按照权值从小到大排序
{
    return a.w<b.w;
}

int Find(int x)
{
    if(F[x]==-1)
        return x;
    else
        return F[x]=Find(F[x]);
}

int Kruskal(int n)///传入点数,返回最小生成树的权值,如果不连通则返回-1
{
    memset(F,-1,sizeof(F));
    sort(edge,edge+tal,cmp);

    int cnt=0;///计算加入的边数
    int ans=0;
    int u,v,w,t1,t2;

    for(int i=0;i<tal;++i)
    {
        u=edge[i].u;
        v=edge[i].v;
        w=edge[i].w;

        t1=Find(u);
        t2=Find(v);

        if(t1!=t2)
        {
            ans+=w;
            F[t1]=t2;
            cnt++;
        }
        if(cnt==n-1)
            break;
    }
    if(cnt<n-1)
        return -1;///不连通
    else
        return ans;
}


int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        tal=0;///必须是0
        int u,v,w;
        for(int i=0;i<m;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        printf("%d
",Kruskal(n));
    }
    return 0;
}
/**
4 6
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
5
*/

  

以上是关于克鲁斯卡尔求最小生成树的主要内容,如果未能解决你的问题,请参考以下文章

使用克鲁斯卡尔算法为以下无向图构造出一棵最小生成树,请画出构造的每一步骤

克鲁斯卡尔求最小生成树

克鲁斯卡尔算法求最小生成树

克鲁斯卡尔算法一定要画图吗

Prim普利姆与Kruskal克鲁斯卡尔算法(Java版)

ACM第四站————最小生成树(克鲁斯卡尔算法)