最小生成树--Kruskal算法

Kruskal算法

Kruskal算法将无向图中的每一个点看做一个单独的集合(即一个连通图)。事先需要对所有权值进行排序,之后按由小到大的次序取权值。从第一个顶点开始找最小的边,并将第二个顶点设置为与第一个点连通,以此循环。

其中该算法需要用到不相交集(并查集)来实现Kruskal算法。

其中不相交集有三个主要的函数

    Make-set(x)      建立一个新的集合,其唯一成员就是x。

   UNION( x , y )    将包含x和y的动态集合合并为一个新的集合。假定在这个操作之前两个集合是不相交的。在经过此操作之后,所得集合的代表可以是Sx 和 Sy的并集中的任何      元素。

   FIND-SET ( x )    返回一个指针,指向包含 x 的集合的代表。

Kruskal算法的时间复杂度为 O(ElgE) 。


代码实现

#include 
#include 
using namespace std;
const int maxn = 10000;
struct edge
{
    int a ,b;
    int weight;
    bool operator <(const edge& cur) const
    {
        return weight < cur.weight;
    }
};

int parent[maxn]; 
edge e[maxn];
edge mst[maxn];  //生成树的数组

void makeset( int n)
{
    for( int i = 0 ; i < n; i++)
        parent[i] = i;
}

int getparent(int i)
{
    if(parent[i] != i)
    {
        parent[i] = getparent(parent[i]);
    }
    return parent[i];
}

//假定可以合并,可以合并则合并返回真,不能合并则返回假
bool unionset(int father , int  son)
{
    int  f = getparent(father);
    int  s = getparent(son);
    if( f  ==  s)
        return false;
    parent[s]  = f;
    return true;
}

//节点0打印为节点A
//仅提供主函数在节点数目很小的情况下使用,方便检查边
char trans( int  i)
{
    return i+'A';
}

int main()
{
    int  n , m ;    //顶点个数  ,边数
    int  k = 0;
    int weight_sum = 0;
    cin >> n >> m;
    for( int i = 0; i < 2*m; i++) //假定输出无向图的边,其边数为2*m
    {
        cin >> e[i].a >> e[i].b >> e[i].weight;
    }

    makeset(n);
    sort(e,e+2*m);  //排序

    for( int i = 0 ; i != 2*m; i++)
    {
        if(unionset(e[i].a , e[i].b))
        {
            mst[k++] = e[i];
            weight_sum += e[i].weight;
        }
    }

    //输出mst
    for( int i = 0 ; i != k ;i++)
    {
        cout << trans(mst[i].a) << "->" << trans(mst[i].b) << " " << "weight= "<< mst[i].weight <

你可能感兴趣的:(算法,算法,kruskal,并查集)