一.概念(可看可不看)
Kruskal算法是一种贪心算法,我们题目中所给的图中的每个边按照权重大小(也就是边的长度)进行排序,每次从边集中取出权重最小(边最小)且两个顶点都不在同一个集合的边加入生成树中!注意:如果这两个顶点都在同一集合内,说明已经通过其他边相连,因此如果将这个边添加到生成树中,那么就会形成环。这样反复做,直到所有的节点都连接成功。这就是krusal算法的操作步骤。
二.图解(比概念理解强多了)
对于这样的一个图,如果让我们将所有点连接起来,也就是连接起来后没有孤立的点,让我们求所有用来连接两个点的边的和的最小值,我们就可以用kruskal算法。
1.我们现将所有边从小往大排序,排好序后,我们发现边长为1的那条边最小,这时候将点V1加入集合中。
2.之后,我们发现V6与V7之间的边长也为1,此时将这条边也加入组合中。
3.这时候,我们继续操作
4.这时候我们发现虽然3是目前边中最小的长度,但如果我们取V2到V4这条边的话,不难发现,V2与V4已经可以通过V1连接起来,加上这条边,只会使我们总长度变大,故我们跳过这条边(这就是避免成环的原因),找长度为4的边。
5.当我们到达这一步是不难发现,我们实际上已经连接起来的所有的点,最后我们把多余边去掉看一下最终结果。
6.最后我们把所有边加起来即为所求。
三.代码(当板子使用即可)
实例:
点的个数 7
边的个数 12
边:
1 2 2
1 4 1
1 3 4
2 4 3
2 5 10
3 4 2
3 6 5
4 5 7
4 6 8
4 7 4
5 7 6
6 7 1
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1;
const int INF =0x3f3f3f3f;
int n;//点的数目
int m;//边的数目
struct edge{
int u,v,w;
}e[N];
int f[N],cnt,ans;
bool cmp(edge x,edge y){
return x.w<y.w;//让权重即边的长度从小到大排序
}
int find(int x){//并查集
if(f[x]==x){
return f[x];
}
f[x]=find(f[x]);
return f[x];
}
void kruskal(){
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int u=find(e[i].u);
int v=find(e[i].v);
if(u==v){//判断是否在同一棵树,如果在则跳过,实际上是为了避免成环
continue;
}
ans+=e[i].w;
f[v]=u;//v的父亲为u,使用并查集的思想,表示(u,v)这条边加入了
cnt++;
if(cnt==n-1) break;//加入n-1条边表示已经构成一棵树
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){//并查集中的初始化操作
f[i]=i;
}
for(int i=1;i<=m;i++){
cin>>e[i].u>>e[i].v>>e[i].w;
}
kruskal();
cout<<ans<<endl;//总权重
system("pause");
return 0;
}
如果你求出最后结果为16,完结撒花!!!
入坑不易,轻点关注!