算法基础22-最小生成树

2023-05-16

最小生成树

  • prim
  • kruskal

prim

链接: acwing上一个关于prim很好的题解

prim 算法干的事情是:给定一个无向图,在图中选择若干条边把图的所有节点连起来。要求边长之和最小。在图论中,叫做求最小生成树。

prim 算法采用的是一种贪心的策略。

每次将离连通部分的最近的点和点对应的边加入的连通部分,连通部分逐渐扩大,最后将整个图连通起来,并且边长之和最小。

//AcWing 858. Prim算法求最小生成树
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 510;

int g[N][N];//稠密图,用邻接矩阵存储
int st[N];//记录生成树中已经添加了哪些节点
int pre[N];//记录每个节点是由哪个节点连接如生成树的
int dist[N];//!!记录每个节点到生成树的距离

int n, m;

void prim()
{
    int res = 0;//最小生成树权值总和
    memset(dist, 0x3f, sizeof dist);
    memset(pre, -1, sizeof pre);
    dist[1] = 0; 
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )//遍历一遍所有节点,找剩余节点中和生成树距离最短的点
        {
            if (!st[j] && (t == -1 || dist[j] < dist[t]))//
            {
                t = j;
            }
        }
        
        //2022.6.1 发现测试用例加强后,需要判断孤立点了
        //如果孤立点,直返输出不能,然后退出
        if(dist[t] == 0x3f3f3f3f) 
        {
            cout << "impossible";
            return;
        }
        
        st[t] = 1;//将找到的节点加入生成树
        res += dist[t];//给生成树的权值赋值
        for (int i = 1; i <= n; i ++ )//遍历所有节点,用刚刚加入的新节点去 更新不在生成树中的节点(或者说剩余节点)距离生成树的距离
        {
            if (!st[i] && dist[i] > g[t][i])//如果不是生成树中的节点 
            {                               //并且 这个节点距离生成树的距离 < 新加入生成树节点t在图中和它之间的距离
                dist[i] = g[t][i];          //就更新
                pre[i] = t;                 //更新之后i距离生成树最短距离的前驱节点设置为t
            }
        }
    }
    cout << res;//返回最小生成树的权重
}

int main()
{
    memset(g, 0x3f, sizeof(g));//邻接矩阵初始化
    cin >> n >> m;
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[b][a] = g[a][b] = min(g[a][b], c);//a,b之间可能有多条边,存最短的就行了
    }
    
    prim();
     //getPath();//输出各个节点添加进最小生成树顺序,也可以说是输出路径
    return 0;
}

优化:

上面代码的时间复杂度为 O(n^2)。

与Dijkstra类似,Prim算法也可以用堆优化,优先队列代替for循环查找距离生成树中最短距离的节点。
优化的Prim算法时间复杂度O(mlogn)。适用于稀疏图,但是稀疏图的时候求最小生成树,Kruskal 算法更加实用。(因为kruskal算法是遍历边,每次找图里面不在生成树中最短的边)

kruskal

算法思路:

  • 将所有边按照权值的大小进行升序排序,然后从小到大一一判断。

  • 如果这个边与之前选择的所有边不会组成回路,就选择这条边分;反之,舍去。

  • 直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。

  • 筛选出来的边和所有的顶点构成此连通网的最小生成树。

  • 判断是否会产生回路的方法为:使用并查集。

  • 在初始状态下给各个个顶点在不同的集合中。、

  • 遍历过程的每条边,判断这两个顶点的是否在一个集合中。

  • 如果边上的这两个顶点在一个集合中,说明两个顶点已经连通,这条边不要。如果不在一个集合中,则要这条边。

可以发现kruskal遍历的是一条一条边,因此只要将图的所有边存下来就行了
也正是因此,kruskal比较适合找出稀疏图的最小生成树

//AcWing 859. Kruskal算法求最小生成树
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 100010;
int p[N];

struct E{
    int a;
    int b;
    int w;
    bool operator < (const E& rhs){//sort是根据数据结构自己的<运算符进行排序的,
                                    //因此我们要重定义结构体的运算符
        return this->w < rhs.w;
    }

}edg[N * 2];//边数为m,m=2*n,其实算是稀疏图了,如果m=n*n那算稠密图了
int res = 0;//最小生成树的权值

int n, m;
int cnt = 0;
int find(int a){//并查集模版,查找该集合内的父节点
    if(p[a] != a) p[a] = find(p[a]);
    return p[a];
}
void kruskal(){
    for(int i = 0; i < m; i++)
    {
        int pa = find(edg[i].a);//表示a所在的集合的父节点
        int pb = find(edg[i].b);//表示b所在的集合的父节点
        if(pa != pb){//判断a,b是否已经在一个集合内,如果在一个集合内还合并的话就会造成回路,就不符合树的定义了
            res += edg[i].w;//收最小生成树的集权值
            p[pa] = pb;//a所在集合的父节点 = b所在集合的父节点
            cnt ++; //记录加入生成树的边数,
        }
    }
}

int main()
{

    cin >> n >> m;
    for(int i = 1; i <= n; i++) p[i] = i;//初始化并查集
                                        //节点下标从1开始,所以 i从1开始
    for(int i = 0; i < m; i++){//初始化边集合数组
        int a, b , c;
        cin >> a >> b >>c;
        edg[i] = {a, b, c};
    }
    sort(edg , edg + m );//每次取最短的边,因此提前将边数组排序,到时候直接从头开始就遍历就是最小的
    kruskal();
    
    if(cnt < n - 1){//如果加入的边数小于n-1说明最小生成树不存在
        cout<< "impossible";
    }
    else cout << res;
    return 0;
}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法基础22-最小生成树 的相关文章

  • 手把手系列--STM32H750移植FreeRTOS(三)--获取CPU占用

    一 目的 在之前的博文中我们移植验证了STM32H750XBH6上运行FreeRTOS系统 xff0c 在实际项目开发中我们经常会遇到获取系统实时运行负载的情况 xff0c 进而对系统进行优化 手把手系列 STM32H750移植FreeRT
  • 【资料分享】工程师必备嵌入式资料合集

    对于许多电子工程师来说 xff0c 各种电路资料 xff0c 学习资料 xff0c 新新技术资料等等 xff0c 都有越多越好的 本篇帖子就为大家整理了一些比较受工程师欢迎的一些电路资料 如果你有心动的话 xff0c 不妨就来搜集一波吧 x
  • HTML网页Javascript跳转代码

    有时候咱们不希望在该页面出现一条长长的链接 xff0c 那就可以采用跳转页了 xff0c 以下是代码 lt html gt lt head gt lt meta http equiv 61 34 Content Type 34 conten
  • 一起尝试写一个自己的小软件

    一起尝试写一个自己的小软件 xff0c 有时候写个小软件 xff0c 会耗费一两个小时 xff0c 有时候耗费几个小时 xff0c 甚至几天 xff0c 但是在写小软件的过程中 xff0c 咱们都是沉浸在软件写好后的美妙体验中 xff0c
  • 网页被挂马了怎么办呢

    首先 xff0c 咱们了解一下网页挂马是什么意思 xff1a 网页挂马指的是把一个木马程序上传到一个网站里面然后用木马生成器生一个网马 xff0c 再上到空间里面 xff01 再加代码使得木马在打开网页时运行 xff01 接下来讲怎么办 如
  • 公司里最看重的是发展机会

    公司里最看重的是发展机会 xff0c 而不是现在的工资 xff0c 这是很多老板都喜欢说的 说的多了 xff0c 咱么那就相信了 虽然说 xff0c 很大程度上 xff0c 今后的日子怎么过 xff0c 取决于现在的想法和奋斗 xff0c
  • 处在八零末期,九零早期,缝隙中的人

    处在八零末期 xff0c 九零早期 xff0c 缝隙中的人 思想既可以与八零年代的人相似 xff0c 又有九零年代那种无法脱掉的稚气 这就是89年 90年出生的人 的特性
  • 马上就下班回家了,让我再写一篇

    马上就下班回家了 xff0c 让我再写一篇 xff0c 写博客让我突然静下来了 同时都纷纷离开了 快了 xff0c 快了 xff0c 马上写好了
  • 我知道自己的未来需要什么

    我知道自己的未来需要什么 xff0c 现在的路就在眼前 xff0c 争取一把 xff0c 奋斗一段时间 xff0c 未来光明坦途正在招手 下班了 xff0c 下次再来
  • 走马观花之《视觉SLAM十四讲》

    1 视觉SLAM 系统概述 SLAM 是Simultaneous Localization and Mapping 的缩写 xff0c 中文译作 同时定位与地图构建 它是指搭载特定传感器的主体 xff0c 在没有环境先验信息的情况下 xff
  • 硬件工程师必会模块之MOS管构成的基本门逻辑电路—看芯片手册框图必备技能

    本文你可以获得什么 xff1f MOS管构成的缓冲器Buffer和漏极开路们OD门是数字电路非常重要的概念 xff0c 怎么构成的 xff1b 反相器 xff0c 线与逻辑怎么玩 xff0c 又怎么用呢 xff1f 根据原理图 xff0c
  • 关于信号量的作用范围

    最近在搞信号量的时候产生了怀疑 xff0c 信号量的作用范围和信号量在任务的位置时候有关系呢 xff1f 答案是有的 xff0c 其实信号量的作用范围是指的从信号量开始到程序的跳转点为止 xff0c 比如一个任务中 xff0c 把信号量放在
  • UNIX 环境高级编程之我见

    UNIX环境高级编程 xff08 第二版 xff09 xff08 人民邮电出版社 xff09 美 W Richard Stevens amp Stephen A Rago 著 本书的主要结构分为以下几个部分 xff1a xff08 1 xf
  • xShell连接ubuntu不成功

    操作环境 xff1a xShell6 43 vm15 43 ubuntu18 04 xShell中以root身份连接虚拟机中的ubuntu时 xff0c 连接不上 xff0c 见下图 xff1a 密码输入的也是对的 xff0c 也能够双向p
  • mac brew install

    brew cask install myprogram base darren 64 Darren 2 project brew cask install docker Error Unknown command cask brew ins
  • mac/linux 系统批量计算文件md5命令

    find type f print0 xargs 0 md5
  • 链表-设计链表

    leetcode 707 设计链表 注意 xff1a 面向对象的思想 这是创建一个自己的链表 xff0c dummyhead和 size初始化都在构造函数中 xff0c 同时自己的链表类也需要定义自己的节点 struct LinkNode链
  • KVM虚拟机使用桥接方式时和宿主机无法通信的解决方案

    KVM虚拟机使用桥接方式时和宿主机无法通信的解决方案 应用场景 虚拟机客户机安装完成后 xff0c 需要为其设置网络接口 xff0c 以便和主机网络 xff0c 客户机之间的网络通信 事实上 xff0c 如果要在安装时使用网络通信 xff0
  • android 电池充电状态记录

    摘抄源码记录下 http androidxref com 9 0 0 r3 xref frameworks native include batteryservice BatteryServiceConstants h This file
  • python 输入三个变量,然后按小到大输出(解析)

    python 实例解析 xff08 1 xff09 vim 2 python py x 61 int input 39 please input x 39 y 61 int input 39 please input y 39 z 61 i

随机推荐

  • Linux系统调用Hook姿势总结

    http www cnblogs com LittleHann p 3854977 html 主题 Linux 相关学习资料 http xiaonieblog com post 61 121 http hbprotoss github io
  • 利用WireShark进行DNS协议分析

    一 准备工作 系统是Windows 8 1Pro 分析工具是WireShark1 10 8 Stable Version 使用系统Ping命令发送ICMP报文 二 开始工作 打开CMD exe键入 ping www oschina net
  • DNS协议详解及报文格式分析

    DNS协议详解及报文格式分析 Posted on 2017 06 18 by Jocent No Comments 目录 一 DNS协议理论知识 1 1 域名结构1 2 域名服务器1 3 域名解析过程 二 DNS协议报文格式 2 1 头部2
  • 解密微信数据库文件解析

    图解说明 xff1a 微信大量数据存储在本地比如 xff1a 联系人 xff08 包含好友地区 电话 通过那种方式添加 xff09 聊天内容 xff08 图片 文字 语音 视频 位置 名片 其他app分享链接 xff09 聊天室 收藏信息
  • qgroundcontrol二次开发环境搭建

    参考考qgroundcontrol官方文档 xff0c 做一些准备工作 xff1a https dev qgroundcontrol com master en getting started index html 1 按官方文档下载qgr
  • Android通过注解来初始化控件

    Android通过注解来初始化控件 对于Android大神的思想与能力我只能膜拜与学习了 xff0c 这里就从大神哪里学来的通过注解来初始化控件简单的概述一下 xff0c 省去了那么繁琐的findViewById步骤 xff08 找到了还要
  • KEIL MDK 工程中头文件包含的路径详解

    xff08 参考工程详见https download csdn net download tianzhijiaoxin 87464281 xff09 文章目录 前言一 include lt h gt 与include 34 h 34 的区别
  • 51-单片机---定时器0和定时器1---8位自动重装载(模式2)-16位定时计数(模式1)

    16位定时计数 xff08 工作方式1 xff09 初始化函数 void timer init TMOD 61 0x01 TH0 61 0x4C TL0 61 0x00 EA 61 1 ET0 61 1 TR0 61 1 初始化定时器运行
  • 算法基础21-图的最短路问题通解

    最短路问题通解 单源最短路所有边权都是正数朴素Dijkstra算法堆优化版Dijkstra算法 存在负权边bellman fordspfaspfa判断是否存在负权环路 单源最短路小结 多源汇最短路floyd 总结 想一想各种最短路算法模版和
  • Visual Studio 2008学习过程(之二)与MATLAB混合编程

    Visual Studio 2008学习过程 之二 MATLAB混合编程 上一篇我写的是我初识VisualStudio2008的过程 后来我又用它开发了几个小程序 至于怎么做的 过两天我再写 这篇文章我就写写VS和MATLAB联合开发程序的
  • HIVE迁移教程X86架构到ARM架构(CPU:鲲鹏920)

    centos8的hive迁移教程 1安装新的centos8环境 2 安装实验所需软件 2 1 安装OpenJDK yum span class token function install span java 1 8 0 openjdk 配
  • C++滑动窗口算法

    滑动窗口算法在一个特定大小的字符串或数组上进行操作 xff0c 而不在整个字符串和数组上操作 xff0c 这样就降低了问题的复杂度 xff0c 从而也达到降低了循环的嵌套深度 如下题 给你两个长度相同的字符串 xff0c s 和 t 将 s
  • C++和js交互方案对比

    c 43 43 和js交互方案对比 一 xff1a nodejs技术 nodejs技术是基于V8引擎的一套前后端交互技术 nan h为c 43 43 提供了与js交互的一系列V8 API 参考链接 缺点 xff1a 在Node js中 xf
  • C++实现HTTP服务

    一个多平台的系统基本架构 xff08 如下图 xff09 xff0c 数据库部分我们以后可以使用HDFS和MapReduce进行分布式存储 xff0c 之前大致介绍了js和c 43 43 交互的几种方式对比 xff0c 考虑到拓展性和访问效
  • gstreamer获取视频采集卡的数据

    gstreamer获取视频采集卡的视频数据 gstreamer可以用于采集硬件视频数据 xff0c 转码 xff0c 播放 xff0c 传输等 xff0c 但由于框架相对于FFmpeg较为小众 xff0c 所以资料较少 xff0c 整理一份
  • 使用c++来实现一个简单的数据库功能

    使用c 43 43 来实现一个简单的文件数据库功能 功能点1 xff1a 建表 1 创建和表同名的文件 2 在文件中存储表的信息 xff0c 包括attribute的name xff0c 数量 xff0c 类型 xff0c 是否唯一 3 添
  • 【性能优化】cpu时间抖动问题的解决修复

    问题描述 xff1a 边缘设备的cpu在低占有率时 xff0c 进程运行时间抖动较大 xff0c 在高占有率时 xff0c 运行时间抖动更稳定 低占有率运行情况图 xff1a 相同处理逻辑循环中 xff0c 两次处理的时间间隔 xff1a
  • pointRCNN 结果可视化

    由于pointRCNN源码的训练和inference很详细 xff0c 但是没有可视化的代码 xff0c 本文介绍其3d框结果的可视化方法 1 跑通pointRCNN https github com sshaoshuai PointRCN
  • C/C++学习笔记——C提高: 函数指针和递归函数

    函数指针 函数类型 通过什么来区分两个不同的函数 xff1f 一个函数在编译时被分配一个入口地址 xff0c 这个地址就称为函数的指针 xff0c 函数名代表函数的入口地址 函数三要素 xff1a 名称 参数 返回值 C语言中的函数有自己特
  • 算法基础22-最小生成树

    最小生成树 primkruskal prim 链接 acwing上一个关于prim很好的题解 prim 算法干的事情是 xff1a 给定一个无向图 xff0c 在图中选择若干条边把图的所有节点连起来 要求边长之和最小 在图论中 xff0c