当前位置: 首页 > article >正文

数据结构与算法学习笔记----Kruskal算法

数据结构与算法学习笔记----Kruskal算法

@@ author: 明月清了个风
@@ first publish time: 2024.12.21

ps⭐️这也是一个思想比较简单的算法,只写了基本思想,具体的可以看代码理解一下

Kruskal算法

Kruskal算法同样是一种基于贪心策略的最小生成树求解算法,另一种是上一篇中的Prim算法。

基本思想

  1. 将所有的边按边长从小到大排序。
  2. 遍历所有边,判断每条边所连接的两个节点是否已经在树中,若没有则将这条边加入生成树,并合并两个节点所在的点的集合。

当树中已经有了 n − 1 n - 1 n1条边时,算法结束,若最后没有 n − 1 n - 1 n1条边,则表示无法生成。

时间复杂度

Kruskal算法的时间复杂度最高的地方为第一步中对所有边的排序,时间复杂度为 O ( m log ⁡ m ) O(m \log m) O(mlogm) m m m为边数,因此这个算法更加适合稀疏图的最小生成树求解问题。

第二步中我们需要进行的操作是将两个点集合并的操作,这个操作可以通过并查集(不知道看这个链接)来实现,对于并查集来说这个是常数级别的操作。

Acwing 859. Kruskal算法求最小生成树

[原题链接](859. Kruskal算法求最小生成树 - AcWing题库)

给定一个 n n n个点 m m m条边的有向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible

给定一张边带权的无向图 G = ( V , E ) G=(V,E) G=(V,E),其中 V V V表示图中点的集合, E E E表示图中边的集合, n = ∣ V ∣ n=|V| n=V m = ∣ E ∣ m=|E| m=E

V V V中的全部 n n n个顶点和 E E E n − 1 n-1 n1条边构成的无向连通子图被称为 G G G的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G G G的最小生成树。

输入格式

第一行包含三个整数 n n n, m m m

接下来 m m m行,每行包含三个整数 x x x y y y z z z,表示存在一条从点 x x x到点 y y y的有向边,边长为 z z z

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible.

数据范围

1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105,

1 ≤ m ≤ 2 ∗ 1 0 5 1 \leq m \leq 2 *10^5 1m2105,

图中涉及边长绝对值均不超过 1000 1000 1000.

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100010, M = N * 2, inf = 0x3f3f3f3f;

struct Edge // 我们需要将所有的边进行排序,因此存储可以选择结构体,重载一下运算符就行了,排序用库函数即可
{
    int a, b, w;
    
    bool operator< (const Edge &W)const   
    {
        return w < W.w;
    }
}edges[M];

int n, m;
int p[N];

int find(int x)   // 并查集的找父节点操作,不知道的画可以看一下上文并查集链接中的文章
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges, edges + m);
    
    for(int i = 1; i <= n; i ++) p[i] = i;  // 初始化并查集
    
    int res = 0, cnt = 0;
    for(int i = 0; i < m; i ++)   // 从小到大遍历所有的边
    {
        auto t = edges[i];
        int a = t.a, b = t.b, w = t.w;
    
        int pa = find(a), pb = find(b);  // 找到这条边两个节点所在的集合
        if(pa != pb)  // 若两个点不在同一个集合中,合并两个点集
        {
            p[pa] = pb;
            res += w;   // 将这条边长加入最小生成树的边权总和中
            cnt ++; // 记录最小生成树中的边数
        }
    }
    
    if(cnt < n - 1) return inf;  // 最小生成树边数小于n - 1,表示生成失败,有点无法连通。
    return res;
}

int main()
{
    cin >> n >> m;
    
    for(int i = 0; i < m; i ++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c};
    }
    
    int t = kruskal();
    
    if(t == inf) puts("impossible");
    else cout << t << endl;
    
    return 0;
}


http://www.kler.cn/a/447791.html

相关文章:

  • 【jvm】主要参数
  • cad c# 二次开发 ——动态加载dll 文件制作(loada netloadx)
  • 精通 Numpy 数组:详解数据类型查看、转换与索引要点
  • SpringBoot 启动类 SpringApplication 二 run方法
  • 2024年12月21日 辩论赛有感
  • Windows中运行Linux(WSL)
  • Moretl非共享文件夹日志采集
  • 计算世界之安生:C++继承的文水和智慧(上)
  • 数据仓库工具箱—读书笔记02(Kimball维度建模技术概述03、维度表技术基础)
  • Cmd命令大全(万字详细版)
  • Python小游戏开发:从零实现贪吃蛇游戏
  • Django-路由
  • 计算机网络:应用层 —— 应用层概述
  • BERT模型入门(12)字节对编码(Byte Pair Encoding,BPE)
  • 【数据库系统概论】—— 关系数据库
  • stm32制作CAN适配器4--WinUsb的使用
  • 植物大战僵尸杂交版v3.0.2最新版本(附下载链接)
  • 云图库平台(二)前端项目初始化
  • 二进制分析的新兴趋势:塑造安全的移动应用
  • Kubernates
  • Ubuntu24版 最新安装CUDA驱动方式
  • dify工作流+github actions实现翻译并创建PR
  • 智能体实战(需求分析助手)二、需求分析助手第一版实现(支持需求提取、整理、痛点分析、需求分类、优先级分析、需求文档生成等功能)
  • Spring(二)AOP、切入点表达式、AspecJ常用通知的类型、Spring中的事务管理
  • 【期末复习】JavaEE(上)
  • powershell美化