求krusal算法原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求krusal算法原理相关的知识,希望对你有一定的参考价值。
如题,,,,,,,,
参考技术A kruskal算法构造G的最小生成树的思想是,首先将G的n个顶点看成是n个孤立的连通分支,将所有的边按权从小到大排序,然后从第一条边开始,依边权递增的顺序查看每一边,并按下述方法连接两个不同的连通分支:当查看到第k条边(v,w)时,如果端点v,w分别是当前两个不同的连通分支T1和T2中的顶点时,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边。这个过程就是G的一棵最小生成树。最小生成树--Boruvka算法
介绍
第一次听说这个算法。。
对于最小生成树一定学过prim和krusal,prim复杂度是
O
(
n
2
)
或
者
O
(
e
l
o
g
n
)
O(n^2)或者O(elogn)
O(n2)或者O(elogn),krusal复杂度是
O
(
e
l
o
g
e
)
O(eloge)
O(eloge),这里介绍一下Boruvka算法
Boruvka算法解决某些特定问题非常好用:
给定n个点,每个点都有点权,任意两个点之间有边权,边权为两个点权用过某种计算方式得出(例如两点权之差),求最小生成树
点的数量为n,边的数量为n^2,当n=1e5,prim和Krusal都会超时,现在用Boruvka求最小生成树的算法:
考虑维护当前的连通块(初始每个点为独立的一个连通块)
对于每个连通块,找到一条与该连通块相连的,且另一端点不在此连通块中的边权最小的边
将所有的这些边加入到最小生成树,注意,当加入一个边时需要判断该点的两端点是否在同一连通块内。
重复若干遍上述操作,直到图连通
复杂度分析:每次连通块的个数至少减半,复杂度为O((n+m)logn),并查集操作是O(1)
本算法不常用于求裸的最小生成树(因为Krusal更好用)
在给出的题目情况中,我们只需要求出每个连通块相连的边权的最小边即可,在这种类型的题目中,这个东西的复杂度一般是O(nlogn)
所以可以在
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)的复杂度下解决此类问题
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
inline int read()
{
int x= 0;
int w= 0;
char ch= 0;
while (ch < '0' || ch > '9')
w|= ch == '-', ch= getchar();
while (ch >= '0' && ch <= '9')
x= (x << 3) + (x << 1) + (ch ^ 48), ch= getchar();
return w ? (-x) : x;
}
#define mp make_pair
const int N= 200005;
const int M= 500005;
const LL inf= 1e12;
int f[N], pd, n, m;
struct node
{
int a, b;
LL c;
} e[M];
pair<LL, LL> E[N];
int find(int k)
{
return (k == f[k]) ? k : f[k]= find(f[k]);
}
LL Boruvka()
{
LL res= 0;
pd= 1;
int num= 0;
for (int i= 1; i <= n; i++)
f[i]= i;
while (num < n - 1) {
int tmp= 0;
for (int i= 1; i <= n; i++)
E[find(i)]= mp(inf, inf);
for (int i= 1; i <= m; i++) {
int fa= find(e[i].a);
int fb= find(e[i].b);
if (fa == fb)
continue;
tmp++;
//取最小的边,最小边一样取最小编号
E[fa]= min(E[fa], mp(e[i].c, i * 1ll));
E[fb]= min(E[fb], mp(e[i].c, i * 1ll));
}
if (tmp == 0)
break;
for (int i= 1; i <= m; i++) {
int fa= find(e[i].a);
int fb= find(e[i].b);
if (fa == fb)
continue;
if ((E[fa] == mp(e[i].c, i * 1ll)) || (E[fb] == mp(e[i].c, i * 1ll))) {
f[fa]= fb;
res+= e[i].c;
num++;
}
}
}
if (num < n - 1)
pd= 0;
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i= 1; i <= m; i++)
scanf("%d%d%lld", &e[i].a, &e[i].b, &e[i].c);
LL ans= Boruvka();
if (!pd)
printf("orz\\n");
else
printf("%lld\\n", ans);
return 0;
}
题目:
以上是关于求krusal算法原理的主要内容,如果未能解决你的问题,请参考以下文章