SDUT最小生成树(并查集实现Kruskal算法)

题目描述

Problem Description

有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的。现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市。

Input

输入包含多组数据,格式如下。
第一行包括两个整数n m,代表城市个数和可以修建的公路个数。(n <= 100, m <=10000)
剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c。

Output

每组输出占一行,仅输出最小花费。
Sample Input

3 2
1 2 1
1 3 1
1 0
Sample Output

2
0

代码 & 分析

求解最小生成树可以使用Prim算法或者Kruskal算法,这是使用的Kruskal算法,原理很直观,首先将所有的边按照权值进行排序,初始的时候所有的节点属于孤立的集合,然后依次选取权值小的边,如果这条边的两个节点分别属于不同的集合,则说明这是最小生成树上的一条边,利用并查集的方法进行合并(也就是将这个结点加入到最小树的集合中来)所有的边都遍历完成之后,如果所有的结点都属于一个集合那么就求得了最小生成树,否则最小生成树不存在。

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<memory.h>
#include<iostream>
using namespace std;
#define N 105
int n,m;
struct edge{
    int a;
    int b;
    int cost;
};
edge e[10005];
int tree[N];
int findroot(int x){          //判断某个点是否为根节点 并降低树高
    if(tree[x]==-1)
        return x;
    else{
        int temp = findroot(tree[x]);
        tree[x] = temp;
        return temp;
    }
}
bool cmp(edge a, edge b){
    return a.cost < b.cost;
}

int main(){
    while(cin>>n>>m){
        memset(tree, -1, sizeof(tree));
        for(int i=0; i<m; i++){
            cin>>e[i].a>>e[i].b>>e[i].cost;
        }
        sort(e, e+m, cmp);
        int ans = 0;
        for(int i=0; i<m; i++){
            int a = findroot(e[i].a);
            int b = findroot(e[i].b);
            if(a!=b){               //判断两个节点是否属于一个集合 否则合并
                ans += e[i].cost;
                tree[a] = b;
            }
        }
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/sinat_34328764/article/details/80154840