欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Borůvka算法学习小记

程序员文章站 2022-07-12 13:46:56
...

概述

Borůvka算法是一种求 \(\text{MST}\)\(n \log n\) 算法 ( \(\text{prim}\space m + n \log n (\text{Fib 堆优化}), \text{kruskal}\space m \log n\) )

思想

可以将其看成多源化的 \(\text{prim}\) 算法

伪代码如下

一开始图中每一个都是一个单独的联通块

当标记为真时:

标记更新为假

对于每一条不在 \(\text{MST}\)上的,连接两个联通块的边 \(\text{u,v}\)(并查集维护):

    如果 len(u, v) 比拓展(指将该联通块连接到另一个联通块上)u 所在联通块的原花费要小,则用前者更新后者
   
    对于 v 所在联通块也是如此
    

对于每一个联通块:

        如果记录的最小花费被更新过,且该记录未被用过(为了防止一条边被重复更新):
        
            标记更新为真
            
            联通块个数-1,答案+=花费
            
                将该边标记为已用,合并这条边连接的两个联通块
            
            

主函数内:

如果联通块个数为1,则该图联通

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5000 + 10, maxm = 200000 + 10;
int n, m, fa[maxn], best[maxn], cnt, ans, used[maxm];
struct edge { int fr, to, w; } e[maxm];
int gf(int x) { return fa[x] == x ? fa[x] : fa[x] = gf(fa[x]); }
void init(int n) { for (int i = 1; i <= n; ++i) fa[i] = i; }
void mer(int a, int b) { if (gf(a) != gf(b)) fa[gf(b)] = gf(a); }
void boruvka() {
    bool flg = true;
    while (flg) {
        flg = false;
        memset(best, 0, sizeof best);
        for (int i = 1; i <= m; ++i) {
            if (gf(e[i].fr) != gf(e[i].to) && !used[i]) {
                int fa = gf(e[i].fr), fb = gf(e[i].to);
                if (e[i].w < e[best[fa]].w) best[fa] = i;
                if (e[i].w < e[best[fb]].w) best[fb] = i;
            }
        }
        for (int i = 1; i <= n; ++i) {
            if (best[i] != 0 && !used[best[i]]) {
                flg = true; cnt ++, ans += e[best[i]].w;
                used[best[i]] = true, mer(e[best[i]].fr, e[best[i]].to);
            }
        }
    }
}
int main() {
    scanf("%d %d", &n, &m); init(n); e[0].w = 0x7fffffff;
    for (int i = 1; i <= m; ++i) scanf("%d %d %d", &e[i].fr, &e[i].to, &e[i].w);
    boruvka();
    if (cnt == n - 1) printf("%d", ans);
    else puts("orz");
    return 0;
}