并查集及其应用——连通数、最小生成树(Kruskal)

代码将很多数组用优先队列替代,利用优先队列(小根堆)自排列的特性,实现每次输出值最小的边。

 

/*
-------------------------------------------------
   Author:       wry
   date:         2022/2/26 20:35
   Description:  FindAndUnion
-------------------------------------------------
*/

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 100+10;

struct Edge{
    int from;
    int to;
    int length;
    bool operator< (Edge e) const {
        return length<e.length;
    }
};

priority_queue<Edge,vector<Edge>,greater<Edge>> edge;    //小根堆,相当于sort(),升序

int father[MAXN];
int height[MAXN];    //根节点height最高,最下面的为0

void Initial (int n) {
    for (int i=0;i<n;i++) {
        father[i] = i;
        height[i] = 0;
    }
}

//找根节点
int Find(int x) {
    if (x!=father[x]) {    //如果不是独立节点
        father[x] = Find(father[x]);   //用递归的方法将其直系父节点变成其父节点的根节点
    }
    return father[x];
}

//合并(小树合并到大树)
int Union(int x,int y) {
    x = Find(x);
    y = Find(y);
    if (x!=y) {
        if (height[x] < height[y]) {
            father[x] = y;
        }
        else if (height[y] < height[x]) {
            father[y] = x;
        }
        else {     //如果节点不同但高度相同
            father[y] = x;
            height[x]++;
        }
    }
}

int Kruskal(int n,int m) {   //n个顶点,m条边,返回最小生成树的权值
    Initial(n);
    int sum = 0;
    for (int i=0;i<m;i++) {
        Edge t = edge.top();
        if (Find(t.from)!= Find(t.to)) {    //如果起点和终点不在同一个树
            Union(t.from,t.to);
            sum += t.length;
        }
        edge.pop();
    }
    return sum;
}

int main() {
    //求连通图数量
    int n,m;   //n个顶点,m条边
    while (cin>>n>>m) {
        if (n==0 && m==0) {
            break;
        }
        Initial(n);
        while (m--) {
            int x,y;
            cin>>x>>y;    //输入边的两个顶点
            Union(x,y);    //将这两个顶点合并在一起(如果是两个新顶点,则走else;如果有已经输入过的点,则走if或者else if)
        }

        //求连通分量数
        int component = 0;
        for (int i=0;i<=n;i++) {
            if (i == Find(i)) {    //自己就是自己的根节点
                component++;
            }
        }
    }

/*    //求最小生成树
    int n;
    while (cin>>n) {
        if (n==0) {
            break;
        }
        int m = n*(n-1)/2;
        for (int i=0;i<m;i++) {
            Edge e;
            cin >> e.from >> e.to >> e.length;
            edge.push(e);
        }
        int answer = Kruskal(n,m);
    }
    return 0;*/
}

  

  

posted @ 2022-02-26 21:38  火星架构师  阅读(81)  评论(0编辑  收藏  举报