Kruskal算法浅显的讲解
Posted Edolon的蒟蒻之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kruskal算法浅显的讲解相关的知识,希望对你有一定的参考价值。
前言
本文 不同步 发表于Luogu Blog
正文
前言*2
最小生成树的定义非常浅显,就是边权值最小的一棵树(给定我们好几种连边方式,来求最小生成树)
求最小生成树有好几种算法
-
- 适用于稠密图的Prim算法(太弱了还没学)
-
- 适用于稀疏图的Kruskal算法(比较简单所以拿捏了)
-
- 没有人知道但是被大佬提过一嘴的 Borůvka (Sollin) 算法(实际上是Prim算法的升级版
更难懂了)
- 没有人知道但是被大佬提过一嘴的 Borůvka (Sollin) 算法(实际上是Prim算法的升级版
本篇Blog先介绍第二种
前置知识
1.并查集
2.知道树是啥玩意
3.贪心(刚讲了肯定会)
正题
Kruskal算法实际上非常简单,我们先来一道例题结合着讲解
很显然,为了求最小生成树,我们先需要存入所有的数据,为了方便,我们使用万能的 结构体
来存数据
struct node
{
int x,y,t;//x表示一个点,y表示另一个点,t表示连接这条边需要的价值(也就是权值)
}k[200005];
然后我们输入数据
for(register int i=1; i<=m;i++)
{
scanf("%d%d%d",&k[i].x,&k[i].y,&k[i].t);
}
最小生成树,肯定得有个求“最小”的过程,这里我们利用贪心的思想,把权值最小的连边放在数组的前面
inline bool cmp(node a,node b)
{
return a.t<b.t;//从小到大排序
}
sort(k+1,k+m+1,cmp);
然后前提准备好了,我们进入程序的主题,即“建树”的环节,这里我们用并查集的思想
inline int find(int x)//路径压缩并查集查找,这里不再细说
{
if(f[x]==x) return f[x];
return f[x]=find(f[x]);
}
int now=0;//现在所建边的权值总数
for(register int i=1; i<=m;i++)
{
if(n==1)//这里需要理解一下,当联通块的数量降为1的时候,我们就已经建好了树,直接输出退出即可(自己画个树试试,边数一定是节点数-1)
{
cout<<now;
return 0;
}
int f1=find(k[i].x),f2=find(k[i].y);//看这俩节点是否连通
if(f1!=f2) //如果不连通
{
f[f1]=f[f2];//让他俩连通
now+=k[i].t;//权值++
n--;//连通块--
}
else continue;
}
cout<<"orz";//如果没有要输出orz
然后这题就AC力
完整AC代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[200005];
inline int find(int x)
{
if(f[x]==x) return f[x];
return f[x]=find(f[x]);
}
struct node
{
int x,y,t;
}k[200005];
inline bool cmp(node a,node b)
{
return a.t<b.t;
}
int main()
{
cin>>n>>m;
for(register int i=1; i<=n;i++) f[i]=i;
for(register int i=1; i<=m;i++)
{
scanf("%d%d%d",&k[i].x,&k[i].y,&k[i].t);
}
sort(k+1,k+m+1,cmp);
int now=0;
for(register int i=1; i<=m;i++)
{
if(n==1)
{
cout<<now;
return 0;
}
int f1=find(k[i].x),f2=find(k[i].y);
if(f1!=f2)
{
f[f1]=f[f2];
now+=k[i].t;
n--;
}
else continue;
}
cout<<"orz";
return 0;
}
然后附一张Kruskal算法的示意图,方便理解
以上是关于Kruskal算法浅显的讲解的主要内容,如果未能解决你的问题,请参考以下文章