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

浙公网安备 33010602011771号