hdu 1233 最小生成树kruskal

http://acm.hdu.edu.cn/showproblem.php?pid=1233

学完kruskal算法,自己的理解就是也是一个贪心的策略,记录下每次的起点和终点,以及他们之间的权值,对边的权值进行排序,每次找出权值比较小的边,判断他与之前所选择的边是否会形成回路,如果不会的话就往生成树中加入这一条边,如果会就舍弃,如何判断回路,就需要用到并查集,找出起点和终点各自的根节点,如果不相同说明是在两个不同的集合之中,(也就意味着不会产生回路)这时候将两个集合合并,并加上这一条边的权值,如果相同就会有回路产生。

附上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 110000
int u[M];
int v[M];
int w[M];
int p[M];
int r[M];
int n,m;
int ans;
int cmp(int i,int j)
{
    return w[i]<w[j];
}
int find(int a)
{
    return p[a]==a?a:p[a]=find(p[a]); //查找根节点并进行路径压缩
}
void kruskal()
{
    for(int i = 0;i < m;i++)
    {
        int e = r[i];
        int x = find(u[e]),y = find(v[e]);
        if(x!=y)//不在同一个集合就不会产生回路,合并两个集合
        {
            p[x] = y;
            ans += w[e];
        }
    }
}
int main()
{
    while(scanf("%d",&n)==1 && n)
    {
        ans = 0;
        m = n*(n-1)/2;
        for(int i = 1;i <= n;i++)
            p[i] = i;
        for(int i = 0;i < m;i++)
            r[i] = i;
        for(int i = 0;i < m;i++)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
        }
        sort(r,r+m,cmp);
        kruskal();
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(hdu 1233 最小生成树kruskal)