当前位置:   article > 正文

最小生成树——Kruskal算法_最小生成树kruskal算法

最小生成树kruskal算法

Kruskal算法简介 & 基本思想

K r u s k a l Kruskal Kruskal算法是一种用于解决最小生成树问题的贪心算法。最小生成树问题是指在一个连通图中找到一棵包含所有顶点的树,且树的边权重之和最小。

K r u s k a l Kruskal Kruskal算法的基本思想是从图中的边集合中选择权重最小的边,并且保证选择的边不会构成环,直到选择了 n − 1 n-1 n1条边为止( n n n为图中顶点的个数)。

Kruskal算法步骤

  1. 将图中的所有边按照边权从小到大进行排序。这可以使用快速排序、归并排序等排序算法来实现,但是通常使用sort排序函数

  2. 创建一个空的边集合,用于存储最小生成树的边。开始时,这个集合是空的。

  3. 创建一个并查集,用于判断选择的边是否会构成环。并查集是一种用于处理不相交集合的数据结构,它支持合并集合和查找元素所属集合的操作。开始时,每个顶点都是一个独立的集合。(关于并查集,请看文章并查集

  4. 遍历边集合,依次选择权重最小的边。

  5. 对于每条选择的边,判断它的两个顶点是否属于同一个集合。这可以通过并查集的查找操作来实现。如果两个顶点属于不同的集合,则选择的边不会构成环,可以将其加入边集合中。

  6. 如果选择的边会构成环,则舍弃该边,继续遍历下一条边。

  7. 重复步骤 4 − 6 4-6 46,直到选择了 n − 1 n-1 n1条边。这样就构建了一棵最小生成树。

Kruskal算法时间复杂度

Kruskal算法的时间复杂度主要取决于对边集合的排序操作,通常为O(ElogE),其中E为边的数量。并查集的操作时间复杂度为O(logV),其中V为顶点的数量。

关于Kruskal的其它

Kruskal算法的优点是简单且易于实现,适用于稀疏图。它不需要事先知道图的具体结构,只需要给出边的集合即可。另外,Kruskal算法可以处理带有负权边的图。

然而,Kruskal算法并不适用于存在负权环的图,因为负权环会导致算法无限循环。此外,Kruskal算法不能处理不连通图,因为最小生成树要求图是连通的。

总结起来,Kruskal算法通过选择权重最小的边,并使用并查集来判断是否构成环,逐步构建最小生成树。它是一种高效且简单的算法,常用于解决最小生成树问题。

Kruskal板题 & 讲解

洛谷P3366【模板】最小生成树

【模板】最小生成树

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N , M N,M N,M,表示该图共有 N N N 个结点和 M M M 条无向边。

接下来 M M M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z i Z_i Zi 的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

样例 #1

样例输入 #1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

样例输出 #1

7
  • 1

提示

数据规模:

对于 20 % 20\% 20% 的数据, N ≤ 5 N\le 5 N5 M ≤ 20 M\le 20 M20

对于 40 % 40\% 40% 的数据, N ≤ 50 N\le 50 N50 M ≤ 2500 M\le 2500 M2500

对于 70 % 70\% 70% 的数据, N ≤ 500 N\le 500 N500 M ≤ 1 0 4 M\le 10^4 M104

对于 100 % 100\% 100% 的数据: 1 ≤ N ≤ 5000 1\le N\le 5000 1N5000 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1M2×105 1 ≤ Z i ≤ 1 0 4 1\le Z_i \le 10^4 1Zi104

样例解释:

所以最小生成树的总边权为 2 + 2 + 3 = 7 2+2+3=7 2+2+3=7

代码

这题非常简单,直接套模板!!

#include<bits/stdc++.h>
using namespace std;
struct edge { int x,y,v; } a[10000000];
int m,n,x,k,ans,f[100000];
int fr(int t)		//并查集的查找祖先函数
{
    if(f[t]!=t)
		f[t]=fr(f[t]);
    return f[t];
}
void mer(int r1,int r2)		//并查集的合并函数
{
    f[fr(r2)]=fr(r1);
}
bool cmp(edge a,edge b)		//sort排序所需的函数
{
    return a.v<b.v;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);	//输入
    }
    for(int i=1;i<=n;i++)	//初始化并查集
		f[i]=i;
    sort(a+1,a+m+1,cmp);	//排序
    for(int i=1;i<=m;i++)	//Kruskal
    {
        if(fr(a[i].x)!=fr(a[i].y))
        {
            mer(a[i].x,a[i].y);
            ans+=a[i].v;
            k++;
        }
        if(k==n-1)
        {
        	printf("%d",ans);
        	return 0;
		}
    }
    printf("orz");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/820675
推荐阅读
相关标签
  

闽ICP备14008679号