2023年--Brouvka算法

 SOl 

1:认为每个点最开始时都是一个点集

2:不断进行更新操作-----进行点集的合并

如何合并呢?

本质则个贪心算法,即每个点集都会找出一条自己“伸”出去的最短边与别人合并

当然对于某条边,可能同时是A集合伸出去的最短边,也是B集合伸出去的。

例如下图的右边,标箭头的就是这个点集伸出去的最短边

 3:找出最短边后,枚举点集,是枚举点集哟。

针对这个点集伸出去的边,如果存在,并且没在MST中的话

则这条边的左右端点所代表的点集,就能合并。

 

 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50,maxm=2e5+5;
const int MaxN = 5000 + 5, MaxM = 200000 + 5;
int N, M;
int U[MaxM], V[MaxM], W[MaxM],Best[maxn];
bool used[MaxM];
int  father[maxn];
void init(int n)
{
	for(int i=1;i<=n;i++)
	    father[i]=i;
}
int find(int x){return x==father[x]?x:father[x]=find(father[x]);}
void unionSet(int x,int y)
{
        int xx=find(x),yy=find(y);
        if(xx==yy) return;
        father[xx]=yy;
}
inline bool Better(int x, int y)
{
    if (y == 0) return true;
//y代表某个点集所伸出去的那条边的编号,如果为0,则说明当前的第x条就是这个点集伸出去的边
//否则,则说明这个点集有多条边伸出去,于是取其是最短的。 if (W[x] != W[y]) return W[x] < W[y]; return x < y; } void Boruvka() { init(N); int merged = 0, sum = 0; bool update = true; while (update) { update = false; memset(Best, 0, sizeof Best); //将每个点集清空 for (int i = 1; i <= M; ++i) //枚举所有的边 { if (used[i] == true) //如果这个边已在MST中,就不管 continue; int p = find(U[i]), q = find(V[i]); //看边的两个点,分别在哪个集合 if (p == q) continue; if (Better(i, Best[p]) == true) //看下第i条边的长度,是否比p这个集合伸出来的边,要更优 Best[p] = i; if (Better(i, Best[q]) == true) Best[q] = i; } for (int i = 1; i <= N; ++i) //枚举所有的点集 if (Best[i] != 0 && used[Best[i]] == false) //如果这个点集有边伸出来了,并且这条边没在MST中 { update = true; //说明有更新操作 merged++; //加了多少条边 sum += W[Best[i]]; //代价加起来 used[Best[i]] = true; //这个边在MST中 unionSet(U[Best[i]],V[Best[i]]); //把这两个集合合并 } } if (merged == N - 1) printf("%d\n", sum); else puts("orz"); } int main() { scanf("%d %d", &N, &M); for (int i = 1; i <= M; ++i) scanf("%d%d%d", &U[i], &V[i], &W[i]); Boruvka(); return 0; }

  

 

https://www.cnblogs.com/glq-Blog/p/16581535.html

 

https://www.zsbeike.com/technology/8e75f8083e.html

 

 

https://www.luogu.com.cn/blog/ETHANK/boruvka-xiao-ji

 

posted @ 2023-10-12 21:56  我微笑不代表我快乐  阅读(59)  评论(0编辑  收藏  举报