解题报告-HDOJ-1233(最小生成树——kruskal)

之前我写过一个最小生成树的prim算法,当时我说过还有另一种求最小生成树的算法,那就是今天要说的——克鲁斯卡尔,如果想学习普林姆的可以翻看我前面写的博客文章http://blog.csdn.net/monkey0le/article/details/7725547

前面说过,prim算法的思想是把点加入到另一个集合中,而kruskal恰好相反,它的思想很简单,不断找最小的边加入进去,并且保证加入边后,仍然是一棵树而不是图,即不存在回路。这里就需要用到上一篇文章中介绍过的并查集,用并查集就可以判断加入边的两个顶点是否已经在这棵树上了。

为了保存边的权值和边的两个顶点,我们定义一个结构体:

typedef struct Edge
{
    int star;
    int end;
    int value;
}Edge;
Edge path[MAXN];

为了找到最小的权值,我们用sort()进行一次排序,sort()函数的用法请参考:http://blog.csdn.net/monkey0le/article/details/7948011 
下面是kruskal的核心代码:

int Kruskal (int n)
{
    init ();		//初始化并查集
    int x = n * (n - 1) / 2;
    sort (path,path + x);
    int sum = 0;
    int count = 0;
    for (int i = 0; i < x && count < n; i++)
    {
        int a = path[i].star;
        int b = path[i].end;
        if (FindRoot (a) != FindRoot (b))	//不在同一个集合
        {
            Union(a,b);		//合并
            sum += path[i].value;	//加入边
            count ++;		//统计边
        }
    }
    return sum;
}

下面是HDOJ-1233题用kruskal实现的代码,我第一次做这题是用prim写的,当时用了93MS,后来用kruskal写用了140MS,但是并不是说prim算法会优于kruskal,只是两种算法适用于不同的图。prim算法的时间复杂度不依赖于排序算法,并且与点的个数有关,适用于稠密图,而kruskal适用于稀疏图。

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 100 + 50;
int father[MAXN];
typedef struct Edge
{
    int star;
    int end;
    int value;
    const bool operator < (const struct Edge &old) const
    {
        return value < old.value;
    }
}Edge;
Edge path[MAXN * MAXN];

int FindRoot (int n)
{
    while (father[n] != n)
    {
        n = father[n];
    }
    return n;
}

void inline Union (int a, int b)
{
    a = FindRoot (a);
    b = FindRoot (b);
    father[b] = a;
}

void init ()
{
    for (int i = 0; i < MAXN; i++)
    {
        father[i] = i;
    }
}

int Kruskal (int n)
{
    init ();
    int x = n * (n - 1) / 2;
    sort (path,path + x);
    int sum = 0;
    int count = 0;
    for (int i = 0; i < x && count < n; i++)
    {
        int a = path[i].star;
        int b = path[i].end;
        if (FindRoot (a) != FindRoot (b))
        {
            Union(a,b);
            sum += path[i].value;
            count ++;
        }
    }
    return sum;
}

int main()
{
    int n;
    while (scanf("%d",&n) != EOF && n)
    {
        int x = n * (n - 1) / 2;
        for (int i = 0; i < x; i++)
        {
            scanf("%d%d%d",&path[i].star,&path[i].end,&path[i].value);
        }
        cout<<Kruskal(n)<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值