Borůvka MST算法

当我认为最MST(最小生成树)已经没有什么学的了,才发现世界上还有个这个kruskal和prim结合的玩意

Borůvka 运用并查集的思想,先将每一个初始点集初始化为有且只有自己的点集,然后每一次合并都从所有的独立集合出发,找到一条权值最小的(权值相同,则编号最小)连向其他集合的边,然后合并集合,很容易看出,每次合并都会使集合总数少一半,合并次数大致为log n

相比之下,Borůvka的合并次数要远远少于其他两个常用的MST算法,但是,毕竟不是一般情况下最快的,但是在求解一些个别的(例如边数多,点数较少的完全图)问题有奇效

 luogu MST的例题,过不去,最后一个点会T,毕竟Borůvka是用来解决完全图的,并不是一般情况下最快的

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 #define LL long long
 4 const int N = 2e5 + 10;
 5 int n,m;
 6 int s[N],t[N],w[N];
 7 struct Boruvka
 8 {
 9     int f[N],use_edge[N],best[N];
10       void init()
11     {
12     for(int i = 1;i <= n;i ++)    f[i] = i,best[i] = 0;
13     for(int i = 1;i <= m;i ++)    use_edge[i] = 0;
14       }
15       int find(int x)
16     {
17           return f[x] == x ? x : (f[x] = find(f[x]));
18       }
19     int better(int x,int y)
20     {
21     if(!y)    return 1;
22     if(w[x] < w[y])    return 1;
23     return x < y;
24       }
25       LL get(void)
26     {
27     int merge=0;
28     LL sum=0;
29     while(merge != n - 1)
30     {
31       for(int i = 1;i <= m;i ++)
32       {
33         if(use_edge[i])    continue;
34         int x = find(s[i]),y = find(t[i]);
35         if(x == y)    continue;
36         if(better(i,best[x]))    best[x] = i;
37         if(better(i,best[y]))    best[y] = i;
38       }
39       for(int i = 1;i <= n;i ++)
40       {
41         if(best[i]){
42               int x = find(s[best[i]]),y = find(t[best[i]]);
43               if(x != y){
44                 use_edge[best[i]] = 1;
45                 f[x] = y;
46                 merge ++;
47                 sum += w[best[i]];
48                       }
49                    best[i] = 0;
50             }
51           }
52     }
53     return sum;
54       }
55 }g;
56 int main(void)
57 {
58        ios::sync_with_stdio(false);
59       cin >> n >> m;
60       for(int i = 1;i <= m;i ++)    cin >> s[i] >> t[i] >> w[i];
61       g.init();
62        cout << g.get() << '\n';
63        return 0;
64 }

 

 

luogu CF888G XOR-MST

 

 很经典的题,题目大意为:

给定一个n个节点的完全图,每个节点有个编号ai,节点i和节点j之间边的权值为ai xor aj,求该图的最小生成树的权值和。

完全图,优先考虑Borůvka

需要在n log n左右的时间中求出每个连通块最小的连接的边,在这道题中边权可以通过点权求出
但是,这是不能直接算出每条边的边权的,因为这一看就是会超时的

所以根据二进制的性质,考虑建对全局建一个01trie,然后再给每一个连通块建一个tire,Borůvka算法每一次合并两个连通块,就合并两个tire,再在trie上维护子树的size,点权异或最小值就直接在全局trie与当前连通块的size作差得到树上贪心即可

总共会迭代log n次,总时间复杂度为O(n logn logsize ),空间复杂度为O(n log size)

 code,仅供参考,没有注释

 1 #include"bits/stdc++.h"
 2 #define ll long long
 3 #define inl inline
 4 #define reg register
 5 #define ls ch[now][0]
 6 #define rs ch[now][1]
 7 using namespace std;
 8 const int N = 2e5 + 10;
 9 const int inf = 0x7ffffff;
10 
11 int L[N * 40],R[N * 40];
12 int ch[N * 40][2];
13 int tot;
14 int n,a[N],root;
15 inl int read(void)
16 {
17     int x = 0,f = 1;char ch = getchar();
18     while(!isdigit(ch)) f = ch == '-' ? - 1 : f,ch = getchar();
19     while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0',ch = getchar();
20     return x * f;
21 }
22 inl void Insert(int &now,int x,int dep)
23 {
24     if(!now) now = ++ tot;
25     L[now] = min(L[now],x),R[now] = max(R[now],x);
26     if(dep < 0) return;
27     int bit = a[x] >> dep & 1;
28     Insert(ch[now][bit],x,dep - 1);
29 }
30 inl int query(int now,int val,int dep)
31 {
32     if(dep < 0) return 0;
33     int bit = val >> dep & 1;
34     if(ch[now][bit]) return query(ch[now][bit],val,dep - 1);
35     else return query(ch[now][bit ^ 1],val,dep - 1) + (1 << dep);
36 }
37 inl ll dfs(int now,int dep)
38 {
39     if(dep < 0) return 0;
40     if(R[ls] && R[rs])
41     {
42         int minn = inf;
43         for(int i = L[ls];i <= R[ls];i ++) minn = min(minn,query(rs,a[i],dep - 1));
44         return dfs(ls,dep - 1) + dfs(rs,dep - 1)+ minn + (1 << dep);
45     }
46     if(R[ls]) return dfs(ls,dep - 1);
47     if(R[rs]) return dfs(rs,dep - 1);
48     return 0;
49 }
50 int main(void)
51 {
52     n = read();
53     for(int i = 1;i <= n;i ++) a[i] = read();
54     sort(a + 1,a + 1 + n);
55     memset(L,0x3f,sizeof(L));
56     for(int i = 1;i <= n;i ++) Insert(root,i,30);
57     printf("%lld\n",dfs(root,30));
58     return 0;
59 }

 

posted @ 2024-01-04 20:00  Ech0_7  阅读(70)  评论(0)    收藏  举报