最小生成树-Kruskal算法

一、概述:

Kruskal算法也是一种求得最小生成树的算法,与Prim算法不同的是,它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树(有关最小生成树的概念和Prim算法见最小生成树-Prim算法)。

二、原理:

Kruskal算法是一种贪心的思想,其原理是,设最小生成树的集合为S,先将无向图中的每一条边由小到大排序,然后从小到大依次将边加入S中,每次加入时需要先判断将此边加入生成树中是否成环,重复上述过程,直至生成树中包含所有的点。判断是否成环需要用到并查集这种数据结构。


图示:
image

三、示例代码(畅通工程)

Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
Sample Output
3
5

#include <bits/stdc++.h>

using namespace std;

int n;
int pre[105]; // 记录根节点
struct edge{
    int v1; // 顶点
    int v2; // 顶点
    int weight; // 权值
};

// 并查集-查
int Search(int root) {
    if(root != pre[root]) {
        root = Search(pre[root]);
    }
    return pre[root];
}

// 并查集-并
void Merge(int root1, int root2) {
    int a, b;
    a = Search(root1), b = Search(root2);
    if(a != b) {
        pre[a] = b;
    }
}

bool cmp(edge x, edge y) {
    return x.weight < y.weight;
}

int Kruskal(edge Edge[]) {
    // ans记录权值之和,cnt记录当前生成树中边的个数
    int ans = 0, cnt = 0, u, v;

    // 将边集合排序
    sort(Edge+1, Edge+n * (n - 1) / 2+1, cmp);

    for (int i = 1; i <= n * (n - 1) / 2; ++i) {
        // 已找出最小生成树,退出循环
        if(cnt >= n-1) break;

        // 取最小权值的边
        u = Edge[i].v1;
        v = Edge[i].v2;

        // 不成环则加入最小生成树
        if(Search(u) != Search(v)) {
            ans += Edge[i].weight;
            cnt++;
            Merge(u, v);
        }
    }
    return ans;
}

int main() {


    int a, b;
    while(~scanf("%d", &n)) {
        if (!n) break;
        int ans = 0, cost;
        edge Edge[n*(n-1)/2+5];
        // 数组初始化
        for (int i = 1; i <= n; ++i) {
            pre[i] = i;
        }

        for (int i = 1; i <= n * (n - 1) / 2; i++) {
            cin >> a >> b >> cost;
            Edge[i].v1 = a;
            Edge[i].v2 = b;
            Edge[i].weight = cost;
        }
        ans = Kruskal(Edge);
        cout << ans << endl;
    }
    return 0;
}
posted @ 2021-08-30 19:48  湖上的程序员  阅读(641)  评论(0编辑  收藏  举报