适用情景
- Kruskal算法主要运用在最小生成树问题当中,适用的情景是在稀疏图(n ~ m)的情况之下,对于稠密图而言用prim算法。
时间复杂度
- 因为并查集的话是很快的,它时间复杂度几乎接近于O( 1 ),然后kruskal算法主要的消耗就在排序上面,所以时间复杂度为MlogM,但是在实际过程当中非常快
算法解释
- 在这个算法当中需要用到之前的并查集知识,因此在一开始的话,需要写好并查集的find函数,并且对于并查集的parent的数组需要初始化一下,也就是说一开始的话是把每一个点都当成是一个孤立的集合
int parent[N];
int find(int x)
{
if (parent[x]!=x)
{
parent[x]=find(parent[x]);
}
return parent[x];
}
for (int i=1;i<=n;i++) //n表示点的数量
{
parent[i]=i;
}
- 然后在这个算法里面不需要用邻接表或者邻接矩阵去存图,因为在这个算法里面,只需要去枚举每一条边就可以,因此对于边的存储只需要用一个结构体数组就可以
typedef struct edge
{
int a;
int b;
int w;
}edge;
edge arr[m];
- 先呢把图里面的每一条边都存到结构体数组里面去
edge arr[m];
int aa,bb,cc;
for (int i=0;i<m;i++)
{
scanf("%d %d %d",&aa,&bb,&cc);
arr[i].a=aa;
arr[i].b=bb;
arr[i].c=cc;
}
- 把每一条边存到结构体数组之后,需要把所有边按权重给它从小到大排序一下
int cmp(const void* e1, const void* e2)
{
edge* p1=(edge*)e1;
edge* p2=(edge*)e2;
return (p1->w)-(p2->w);
}
qsort(arr,m,sizeof(edge),cmp);
- 还要创建一个变量cnt,这个变量主要用来记录一下当前已经加入了多少条边到这个联通块集合(这个联通块集合不断壮大的话,最后就是我要求的最小生成树)当中.
int cnt=0;
- 然后这个结构体数组就已经按所有边的权重从小到大已经排序好了,然后就是从前往后枚举每一条边,每次枚举的时候,对于你枚举的每一条边(a点指向b点,权重为w),去判断一下a,b这两个点到底有没有联通?如果说这两个点还没有联通的话,把他们放到一个集合里面,就是说把他们联通起来,然后整个最小生成树的边的总权重和去加上这条边的权重,相当于就是说该边已经被加入到最小生成树当中,所以说变量cnt的话也需要加1
int res=0;
for (int i=0;i<m;i++)
{
int a=arr[i].a;
int b=arr[i].b;
int w=arr[i].w;
if (find(a)!=find(b))
{
cnt++;
res+=w;
parent[find(a)]=find(b);
}
}
- 当把每一条边从小到大这么枚举完了之后,当循环退出来的时候,去判断一下这个cnt,因为如果你这个无向图的最小生成树它是存在的话,根据最小生成树以及树形数据结构的定义,这棵树必须得包含原先图的所有的n个点,且得有n-1条边,所以说就去判断一下这个cnt变量是否等于n-1,如果说小于n-1的话,就说明不存在最小生成树
if (cnt<n-1)
{
printf("impossible\n");
}
else
{
printf("%d\n",res);
}
例题
来源:AcWing
Kruskal
#include <stdio.h>
#include <stdlib.h>
#define N 100010
#define M 200020
typedef struct edge
{
int a;
int b;
int w;
}edge;
int parent[N];
int find(int x)
{
if (parent[x]!=x)
{
parent[x]=find(parent[x]);
}
return parent[x];
}
int cmp(const void* e1, const void* e2)
{
edge* p1=(edge*)e1;
edge* p2=(edge*)e2;
return (p1->w)-(p2->w);
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++)
{
parent[i]=i;
}
edge arr[m];
int aa,bb,ww;
for (int i=0;i<m;i++)
{
scanf("%d %d %d",&aa,&bb,&ww);
arr[i].a=aa;
arr[i].b=bb;
arr[i].w=ww;
}
qsort(arr,m,sizeof(edge),cmp);
int cnt=0;
int res=0;
for (int i=0;i<m;i++)
{
int a=arr[i].a;
int b=arr[i].b;
int w=arr[i].w;
if (find(a)!=find(b))
{
cnt++;
res+=w;
parent[find(a)]=find(b);
}
}
if (cnt<n-1)
{
printf("impossible\n");
}
else
{
printf("%d\n",res);
}
return 0;
}