详解最小生成树——Kruskal算法(prim算法的兄弟版本)

一.概念(可看可不看

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,完结撒花!!!

入坑不易,轻点关注!

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值