算法图论学习-Kruscal最小生成树

140 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

Kruscal生成树

Kruscal生成树是用在图论里的算法用于在无向图中构建最小生成树,在这个算法中我们会用到并查集去维护连通块,排序去贪心处理

实现原理

首先我们将无向边和边权存在一个结构体中对边权进行排序,这样就可以让我们从前往后处理的都是当前数组中未处理代价最小的,每当我们发现当前遍历到的结构体中的u,v,w{u, v, w} | u,v{u, v}分别在的生成树不在一个集合中那我们将这两个生成树(集合)合并当我们遍历结束后如果最大的集合中有了n个点那么这个图就有最小生成树,否则图中不存在最小生成树

实现代码

struct node // 创建结构体
{
    int u, v, w;
    bool operator < (const node &v) const {
        return w < v.w;
    }
}c[N];
int n, m;
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);} // 并查集的查找
int Kruskal() { //Kruskal最小生成树
    int cnt = 0;
    int res = 0;
    for(int i = 1; i <= m; i++) {
         int fa = find(c[i].u), fb = find(c[i].v);
         if(fa != fb) {
             cnt ++;
             res += c[i].w;
             f[fb] = fa; //连通块合并
         }
    }
    if(cnt != n - 1) return - 1;//表示不存在最小生成树
    else return res;
}

[例题](最小生成树2 - 题目 - Daimayuan Online Judge)

Code

const int N = 2e5 + 10;
struct node // 创建结构体
{
    int u, v, w;
    bool operator < (const node &v) const {
        return w < v.w;
    }
}c[N];
int n, m, f[N];
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);} // 并查集的查找
int Kruskal() { //Kruskal最小生成树
    int cnt = 0;
    int res = 0;
    for(int i = 1; i <= m; i++) {
         int fa = find(c[i].u), fb = find(c[i].v);
         if(fa != fb) {
             cnt ++;
             res += c[i].w;
             f[fb] = fa; //连通块合并
         }
    }
    if(cnt != n - 1) return - 1;//表示不存在最小生成树
    else return res;
}
void solve()
{
   cin >> n >> m;
   for(int i = 1; i <= m; i++) cin >> c[i].u >> c[i].v >> c[i].w;
   for(int i = 1; i <= n; i++) f[i] = i;
   sort(c + 1,c + 1 + m);
   cout << Kruskal() << endl;
}