最小生成树算法———Kruskal算法(C++实现)

写在前面

由于本人实力尚浅,接触算法没多久,写这篇blog仅仅是想要提升自己对算法的理解,如果各位读者发现什么错误,恳请指正,希望和大家一起进步。(●’◡’●)

题目

skruskal题目

思路

  1. p[]数组记录每个顶点的祖宗(即每个顶点属于哪个集合),初始时,每个顶点的祖宗都是自己(即每个顶点自己是一个集合)。用cnt记录连通部分用多少条边。
  2. 将每一条边按照边权的大小从小到大排序。
  3. 按顺序取出每一条边,看是否与之前取出的边形成回路,也就是判断边的俩个顶点的祖宗是否相同(即两个顶点是否在同一个集合)。如果祖宗相同就会形成回路,那就不选这条边。如果如果祖宗不同,那就把其中一个顶点置为另一个顶点的祖宗,同时cnt++表示连通部分边数加一。
  4. 遍历完所有的边,判断cntn-1的大小。如果cnt<n-1那就说明图不连通,否则图就连通。

代码

#include<iostream>
#include<algorithm>

using namespace std;
const int N=1e5+10,M=2e5+10;
int p[N];       //用来实现并查集,记录每个顶点的祖宗顶点
int n,m;

struct edge     //定义边的结构体
{
    int a,b,w;
}e[M];

bool cmp(struct edge a,struct edge b)       //比较边权大小的函数
{
    return a.w<b.w;
}

int find(int u)     //寻找祖宗顶点,并且路径压缩
{
    if(u==p[u])
        return u;
    return p[u]=find(p[u]);
}


int Kruskal()
{
    sort(e,e+m,cmp);        //将边按照边权大小排序
    for(int i=1;i<=n;i++)       //对p[]数组初始化,一开始每个顶点的祖宗都是自己
        p[i]=i;
    int res=0;      //记录最后的答案,即最小生成树的所有边的边权
    int cnt=0;      //记录连通部分有多少边,方便最后判断图是否连通
    for(int i=0;i<m;i++)        //遍历每一条边
    {
        int a=e[i].a,b=e[i].b,w=e[i].w;
        a=find(a),b=find(b);        //找到边的两个顶点的祖宗(看俩个顶点是否属于一个集合)
        if(a!=b)        //如果祖宗不同,也就是不在一个集合
        {
            res+=w;
            cnt++;      //连通部分的边数加一
            p[a]=b;     //把a的祖宗置为b
        }
    }
    if(cnt<n-1)     //如果最后连通部分的边数小于n-1,就说明图不连通
        return 0x3f3f3f3f;
    else 
        return res;
}

int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        e[i]={a,b,c};
    }
    
    int res=Kruskal();
    if(res==0x3f3f3f3f)
        cout<<"impossible"<<endl;
    else 
        cout<<res<<endl;
    return 0;
}

说明

  • 这道题中用的到并查集会有很多应用,同时find()函数也非常优美,短短几行代码就可以找到祖宗,同时还能进行路径压缩。后面我看有时间我会专门出一篇blog讲解并查集,这还不赶紧关注博主一波。
int find(int u)     //寻找祖宗顶点,并且路径压缩
{
    if(u==p[u])
        return u;
    return p[u]=find(p[u]);
}
  • 学有余力的童鞋可以对比一下kruskalprim算法(不了解prim?——>传送门),两个算法求解的是同一个问题。

感谢各位童鞋看到这里,后面我会持续更新数据结构与算法,也希望大家点点赞,我们一起进步(❁´◡`❁)

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
最小生成Kruskal算法是一种常用的图算法,用于找到一个连通图的最小生成。下面是Kruskal算法的C++代码示例: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; // 定义边的结构体 struct Edge { int src, dest, weight; }; // 定义并查集的数据结构 classFind { public: vector<int> parent, rank; UnionFind(int n) { parent.resize(n); rank.resize(n); for (int i = 0; i < n; i++) { parent[i] = i; rank[i] = 0; } } int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } void unionSet(int x, int y { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { if (rank[rootX] < rank[rootY]) { parent[rootX] = rootY; } else if (rank[rootX] > rank[rootY]) { parent[rootY] = rootX; } else { parent[rootY] = rootX; rank[rootX]++; } } } }; // Kruskal算法实现 vector<Edge> kruskalMST(vector<Edge>& edges, int V) { // 按照边的权重进行排序 sort(edges.begin(), edges.end(), [](const Edge& a, const Edge& b) { return a.weight < b.weight; }); vector<Edge> result; UnionFind uf(V); for (const Edge& edge : edges) { int src = edge.src; int dest = edge.dest; // 判断加入边后是否形成环路 if (uf.find(src) != uf.find(dest)) { uf.unionSet(src, dest); result.push_back(edge); } } return result; } int main() { int V, E; cout << "请输入顶点数和边数:"; cin >> V >> E; vector<Edge> edges(E); cout << "请输入每条边的起点、终点和权重:" << endl; for (int i = 0; i < E; i++) { cin >> edges[i].src >> edges[i].dest >> edges[i].weight; } vector<Edge> mst = kruskalMST(edges, V); cout << "最小生成的边:" << endl; for (const Edge& edge : mst) { cout << edge.src << " - " << edge.dest << " : " << edge.weight << endl; } return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值