prim
先将一个点加入集合中,维护一个dis数组,表示该点距集合中的点的最小距离,每次选取dis的最小值,并把那个点加入集合,更新dis。
可以用优先队列优化
kruskal
把所有的边按边权从小到大排序,利用并查集维护集合关系,对于每条边,若两点不在同一集合,则把两点连接。
Boruvka
假设每个点都是一个联通块,然后求出与当前联通块最近的一个联通块的距离,然后让两个块联通。
每次联通块的个数都会少一半,所以会执行logn次
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
const int maxn = 201110;
const int M = 1e9+7;
int n,m,k,ok;
vector<pii> v[maxn];
int pre[maxn];
int find(int x)
{
return x==pre[x]?x:pre[x]=find(pre[x]);
}
int link[maxn],val[maxn];
void Boruvka()
{
for(int i = 1; i <= n; i++)
{
pre[i] = i;
}
int ans = 0;
bool flag;
do
{
flag = 0;
mem(link,0);mem(val,inf);
for(int i = 1; i <= n; i++)
{
int x = find(i);
for(auto j : v[i])
{
int y = find(j.first);
if(x == y || j.second >= val[x]) continue; //如果当前联通快和其他联通快之间有更短的边
link[x] = y;val[x] = j.second;
}
}
for(int i = 1; i <= n; i++)
{
int x = find(i);
if(link[x] && x != find(link[x]))
{
pre[x] = find(link[x]);
ans += val[x];
flag = 1;
}
}
} while (flag);
int x = find(1);
for(int i = 1; i <= n; i++)
{
if(find(i) != x)
{
cout<<"orz
";
return;
}
}
cout<<ans<<endl;
}
signed main()
{
cin>>n>>m;
for(int i = 1,x,y,z; i <= m; i++)
{
cin>>x>>y>>z;
v[x].push_back({y,z});
v[y].push_back({x,z});
}
Boruvka();
return 0;
}