【算法基础:搜索与图论】3.5 求最小生成树算法(PrimKruskal)

news2024/11/27 22:34:45

文章目录

  • 最小生成树介绍
  • 朴素Prim算法
    • 算法思路⭐
    • 例题:858. Prim算法求最小生成树
  • Kruskal算法
    • 算法思路⭐
    • 例题:859. Kruskal算法求最小生成树

最小生成树介绍

最小生成树
有关树的定义

生成子图:生成子图是从原图中选取部分节点以及这些节点之间的边所组成的图。生成子图中的所有节点和边都必须在原图中存在。

生成树:一个连通无向图生成子图,同时要求是树。也即在图的边集中选择 n - 1 条,将所有顶点连通。

我们定义无向连通图的 最小生成树(Minimum Spanning Tree,MST)为边权和最小的生成树

注意:只有连通图才有生成树,而对于非连通图,只存在生成森林。

在这里插入图片描述

朴素Prim算法

算法思路⭐

算法流程和 Dijkstra 算法非常相似。

Dijkstra 算法是用 t 更新其它点到起点的距离,而 Prim 用 t 更新其它点到 集合 的距离。

在这里插入图片描述

初始时各个点到集合的距离设置为 INF

循环 n 次,每次循环找到当前没在集合(集合就是最小生成树中节点的集合)且距离集合最近的节点。

将当前最近的节点 t 加入最小生成树中,然后使用 t 更新其它所有点(1~n)到集合之间的距离。

时间复杂度是: O ( n 2 + m ) O(n^2 + m) O(n2+m)

例题:858. Prim算法求最小生成树

https://www.acwing.com/problem/content/description/860/

在这里插入图片描述

注意:图中可能存在重边和自环。
重边是指连接同一对顶点的多条边。在处理重边的时候,我们应当只保留权重最小的那条边,其他的边应当被忽略。
自环是指从一个顶点指向自身的边。在最小生成树中,自环是没有意义的,因为我们可以直接忽略这样的边。实际上,对于 Prim 算法,我们应当在初始化阶段,忽略这些自环,即将其赋予无穷大的权重。

另外注意图是无向图,因此在建图时应当同时更新 g [ u ] [ v ] = g [ v ] [ u ] = M a t h . m i n ( g [ u ] [ v ] , w ) ; g[u][v] = g[v][u] = Math.min(g[u][v], w); g[u][v]=g[v][u]=Math.min(g[u][v],w);

import java.util.*;

public class Main {
    static final int INF = 0x3f3f3f3f;

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), m = scanner.nextInt();
        // 边数很多,所以使用邻接矩阵来存储
        int[][] g = new int[n + 1][n + 1];
        for (int i = 1; i <= n; ++i) {
            Arrays.fill(g[i], INF);     // 对于自环也应该把距离设置成INF
        }
        for (int i = 0; i < m; ++i) {
            int u = scanner.nextInt(), v = scanner.nextInt(), w = scanner.nextInt();
            g[u][v] = g[v][u] = Math.min(g[u][v], w);   // 是无向图,所以g[u][v] = g[v][u]都要更新
        }

        // 求最小生成树的树边权重之和
        int sum = prim(g);
        System.out.println(sum > INF / 2? "impossible": sum);
    }

    static int prim(int[][] g) {
        int n = g.length - 1, res = 0;
        boolean[] st = new boolean[n + 1];      // 存储每个点是否已经在生成树中了
        int[] dis = new int[n + 1];             // 存储其它点到当前最小生成树的距离
        Arrays.fill(dis, 0x3f3f3f3f);       // 初始时距离都是 INF

        for (int i = 0; i < n; ++i) {
            // 找到当前和集合最近且不在集合中的节点t
            int t = -1;
            for (int j = 1; j <= n; ++j) {
                if (!st[j] && (t == -1 || dis[t] > dis[j])) t = j;
            }

            if (i != 0 && dis[t] == INF) return INF;    // 如果第一个节点没有把任何节点到最小生成树的距离变小

            // 将 t 加入最小生成树中去
            if (i != 0) res += dis[t];                  // 注意判断树中的第一个节点是不会贡献边权和的
            st[t] = true;

            // 使用 t 到各个节点的距离 更新 各个节点到当前最小生成树的距离
            for (int j = 1; j <= n; ++j) {
                dis[j] = Math.min(dis[j], g[t][j]);
            }
        }

        return res;
    }
}

Kruskal算法

算法思路⭐

  1. 先将所有边按权重从小到大排序
  2. 枚举每条边 a ,b , w。如果 a, b 不连通就把这条边加入集合,即加入最小生成树。

在这里插入图片描述

如果使用 O ( m log ⁡ m ) O(m\log m) O(mlogm) 的排序算法,并且使用 O ( m α ( m , n ) ) O(m\alpha(m, n)) O(mα(m,n)) O ( m log ⁡ n ) O(m\log n) O(mlogn) 的并查集,就可以得到时间复杂度为 O ( m log ⁡ m ) O(m\log m) O(mlogm) 的 Kruskal 算法。

例题:859. Kruskal算法求最小生成树

https://www.acwing.com/activity/content/problem/content/925/
在这里插入图片描述

import java.util.*;

public class Main {
    static final int INF = 0x3f3f3f3f, N = 100005;
    static int[] p = new int[N];
    static int n;

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        int m = scanner.nextInt();

        // 记录所有的 m 个边
        int[][] edges = new int[m][3];
        for (int i = 0; i < m; ++i) {
            edges[i][0] = scanner.nextInt();
            edges[i][1] = scanner.nextInt();
            edges[i][2] = scanner.nextInt();
        }

        int res = kruskal(edges);
        System.out.println(res == INF? "impossible": res);
    }

    static int find(int x) {
        if (x != p[x]) p[x] = find(p[x]);
        return p[x];
    }

    static int kruskal(int[][] edges) {
        // 按照权重升序排序
        Arrays.sort(edges, (a, b) -> a[2] - b[2]);
        Arrays.setAll(p, e -> e);       // 初始化并查集

        int res = 0, cnt = 0;
        for (int[] edge: edges) {
            int x = edge[0], y = edge[1];
            if (find(x) != find(y)) {
                p[find(x)] = find(y);
                res += edge[2];
                cnt++;
            }
        }

        if (cnt < n - 1) return INF;
        return res;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

16.喝水

喝水 html部分 <h1>Goal: 2 Liters</h1> <div class"cup cupbig"><div class"remained"><span id"liters">2L</span><small>Remained</small></div><div class"percentage&quo…

欧姆龙cp1h-e串口以太网连接怎么设置欧姆龙CX系列

捷米特JM-ETH-CX串口转以太网通讯处理器是为满足日益增多的工厂设备信息化需求&#xff08;设备网络监控和生产管理&#xff09;而设计&#xff0c;用于欧姆龙 CPM、CQM、C200、C1000、C2000 等多个系列 PLC 的以太网数据采集&#xff0c; 非常方便构建生产管理系统。 捷米特J…

【字符流】案例:文件到集合(改进版)

案例&#xff1a;文件到集合&#xff08;改进版&#xff09; 1.需求&#xff1a; 把文本文件中的数据读取到集合中&#xff0c;并遍历集合。要求&#xff1a;文件中每一行数据是一个学生对象的成员变量值 ​ 举例&#xff1a;001,郝佳乐,20,西安 2.思路&#xff1a; 定义学…

Vue第六篇:电商网站图片放大镜功能

本文参考&#xff1a;https://blog.csdn.net/liushi21/article/details/127497487 效果如下&#xff1a; 功能实现分解如下&#xff1a; &#xff08;1&#xff09;商品图区域&#xff1a;主要是浏览图片&#xff0c;根据图片的url显示图片。当鼠标离开此区域时"放大镜区…

HTTP中GET请求和POST请求的区别

前言 HTTP&#xff08;超文本传输协议&#xff09;是用于在 Web 浏览器和 Web 服务器之间传输数据的协议。在 HTTP 中&#xff0c;GET 和 POST 是两种常见的请求方法。一般我们在浏览器输入一个网址访问网站都是 GET 请求&#xff1b;在 FORM 表单中&#xff0c;可以通过设置 …

Mac端简单好用的程序创建工具:VMware InstallBuilder Enterprise

VMware InstallBuilder Enterprise for Mac是一款用于为台式机和服务器软件构建跨平台安装程序的开发工具。使用InstallBuilder&#xff0c;您可以从单个项目文件和构建环境中为Linux&#xff0c;Windows&#xff0c;Mac OS X&#xff0c;Solaris和其他平台快速创建动态&#x…

Windows下mosquitto服务端和MQTT.fx客户端搭建模拟环境

第一部分 Mosquitto安装测试 一、概念梳理 1、Mosquitto是一款实现了消息推送协议MQTT 3.1的开源消息代理软件&#xff0c;提供轻量级的、支持可订阅/可发布的消息推送模式&#xff0c;是设备与设备之间的短消息通信变得简单&#xff0c;广泛应用于低功耗传感器、手机&#xff…

django跨域设置

1.安装 (venv) ***\data_analyse_web>pip install django-cors-headers 2.添加应用 :在settings.py中添加应用,放到任意位置都行 INSTALLED_APPS {# ...corsheaders,# ... } 3. 设置中间层&#xff0c;在settings.py中添加中间层&#xff0c;放到最前面 MIDDLEWARE [c…

【设计模式】23种设计模式——原型模式Prototype(原理讲解+应用场景介绍+案例介绍+Java代码实现)

原型模式 介绍 原型模式指用通过拷贝原型实例创建新的实例&#xff0c;新实例和原型实例的属性完全一致原型模式是一种创建型设计模式工作原理是通过调用原型实例的 clone()方法来完成克隆&#xff0c;原型实例需要实现Cloneable接口&#xff0c;并重写clone()方法需要为每个…

WSR-88D天气雷达工作模式、监测目标、反射率含义讲解

一、WSR-88D 简介 WSR-88D是天气监视多普勒雷达之一。自 1988 年首次建造和测试以来,它已在包括阿拉斯加和夏威夷在内的美国 160 多个地点安装和使用。WSR-88D也已安装在波多黎各和太平洋的几个岛屿。 WSR-88D雷达发射功率为750000瓦(平均灯泡只有75瓦)!这种功率使雷达产…

03. 自定义镜像 Dockerfile

目录 1、前言 2、构建镜像的方式 2.1、docker commit 2.1.1、先查看下当前的容器 2.1.2、生成该容器镜像 2.1.3、查看镜像列表 2.2、Dockerfile 2.2.1、创建Dockerfile文件 2.2.2、编写Dockerfile文件 2.2.3、构建镜像 2.2.4、使用该镜像生成容器 3、Dockerfile 3…

Docker 网络、资源控制

Docker 网络、资源控制 一、Docker 网络1、Docker 网络实现原理2、Docker 的网络模式&#xff1a;1&#xff0e;host模式2&#xff0e;container模式3&#xff0e;none模式4&#xff0e;bridge模式5&#xff0e;自定义网络 二、资源控制1&#xff0e;CPU 资源控制&#xff08;1…

用echarts绘制流程图

getEchart1() {echarts.init(document.getElementById(echart1)).dispose();var chartDom document.getElementById(echart1);this.myChart echarts.init(chartDom);var charts {nodes: [ // 节点{name: 开始, value: [0, 500],label: {borderWidth: 1, // 边框宽度borderRa…

【CMU15-445 FALL 2022】Project #1 - Buffer Pool

About 实验官网 Project #1 - Buffer Pool在线评测网站 gradescope Lab Task #1 - Extendible Hash Table 详见——【CMU15-445 FALL 2022】Project #1 - Extendable Hashing 如果链接失效&#xff0c;请查看当前平台我之前发布的文章。 Task #2 - LRU-K Replacement Polic…

flink Mysql CDC(动态加表)、postgresqlCDC 和 CDC无锁算法

flinkCDC - 功能验证记录 flink 与cdc 版本使用搭配&#xff1a;flink cdc参数说明原理分析&#xff08;DBLog&#xff09;无锁算法论文 mysql cdccdc api 动态加表flink cdc sql 性能压测flink cdc api 性能压测 PostgreSqlCDC执行更新语句&#xff0c;会出现 2 种情况 cdc si…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

[STL]vector使用介绍

[STL]vector使用介绍 注&#xff1a;文内代码均在Visual Studio 2013下进行测试&#xff0c;不同的编译器下在扩容大小等方面可能有所不同&#xff0c;但不影响各接口函数的使用。 文章目录 [STL]vector使用介绍1. vector介绍2. 构造函数3. 迭代器相关函数begin函数和end函数的…

实现点击复制到剪切板功能

该功能使用VueUse实现 什么是 VueUse VueUse不是Vue.use&#xff0c;它是为Vue 2和3服务的一套Vue Composition API的常用工具集&#xff0c;是目前世界上Star最高的同类型库之一。它的初衷就是将一切原本并不支持响应式的JS API变得支持响应式&#xff0c;省去程序员自己写相…

jmeter常用的提取器(正则表达式和JSON提取器)

jmeter常用的后置处理器有两种提取数据&#xff1a; 1、JSON提取器 获取后可以将变量token引用到其他所需要的地方 &#xff08;正则表达式和JSON提取器&#xff09;:2023接口自动化测试框架必会两大神器:正则提取器和Jsonpath提取器_哔哩哔哩_bilibilihttps://www.bilibili.…

uniapp实战

上面是tab栏&#xff0c;下面是swiper&#xff0c;&#xff0c;tab和swiper和 红色滑块 动态变化&#xff0c;&#xff0c; 遇到的问题&#xff1a; 往下滚动 tab栏 吸顶&#xff1a; position:sticky; z-index:99; top:0;swiper切换触发 change 事件&#xff0c; :current …