mst[讲课留档]

最小生成树(Minimum Spanning Tree)

(1)概念

我们知道,是有 n n n个结点, n − 1 n-1 n1条边的无向无环的连通图。

一个连通图的生成树是一个极小的连通子图,它包含图中全部的 n n n个顶点,但只有构成一棵树的 n − 1 n-1 n1条边。

最小生成树就是一个带权图,每个边都有一个边权,一颗生成树的权值是该树边所有边权的和, M S T MST MST就是所有生成树中最小的一个。

(2)Prim算法(遍历点的算法)

普里姆算法在找最小生成树时,将顶点分为两类,一类是在查找的过程中已经包含在生成树中的顶点(假设为 A 类),剩下的为不在生成树中的(假设为 B 类)。

对于给定的连通网,起始状态全部顶点都归为 B 类。在找最小生成树时,选定任意一个顶点作为起始点,并将之从 B 类移至 A 类;然后找出 B 类中到 A 类中的顶点之间权值最小的顶点,将之从 B 类移至 A 类,如此重复,直到 B 类中没有顶点为止。所走过的顶点和边就是该连通图的最小生成树。

请添加图片描述

int dis[N];
int mp[N][N];
bool vis[N];void work() {int n, m;cin >> n >> m;int ans = 0;memset(vis, 0, sizeof vis);memset(mp, 0x3f3f3f3f, sizeof mp);for (int i = 0; i < n; ++i) {int u, v, w;cin >> u >> v >> w;mp[u][v] = w;mp[v][u] = w;}for (int i = 0; i < n; ++i) {dis[i] = 0x3f3f3f3f;}dis[0] = 0;vis[0] = 1;for (int i = 1; i < n; ++i) {dis[i] = min(dis[i], mp[0][i]);}for (int i = 1; i < n; ++i) {//这里的外层循环是循环遍数,与i值无关double minn = 0x3f3f3f3f;int pos = -1;for (int j = 1; j < n; ++j) {//每次循环找出与已排联通块距离最近的点if (!vis[j] && minn > dis[j]) {pos = j;minn = dis[j];}}ans += minn;vis[pos] = 1;for (int j = 0; j < n; ++j) {//刷新未连接点的距离最小值dis[j] = min(dis[j], mp[pos][j]);}}cout << ans << '\n';
}

正确性显然。

复杂度是 O ( n 2 ) O(n^2) O(n2)级别的,但是我们可以使用堆优化降到 O ( n l o g n ) O(nlogn) O(nlogn),之后讲最短路的时候会讲堆优化。

(3)Kruskal算法(遍历边的算法)

克鲁斯卡尔算法(Kruskal)是一种使用贪婪方法的最小生成树算法。 该算法初始将图视为森林,图中的每一个顶点视为一棵单独的树。 一棵树只与它的邻接顶点中权值最小且不违反最小生成树属性(不构成环)的树之间建立连边。

请添加图片描述

利用并查集可以快速实现查找两个点是否已经连接

int n, m;
int f[105];
struct road {int a, b, v;
} arr[305];int find(int a) {if (f[a] == a)return a;elsereturn f[a] = find(f[a]);
}void join(int a, int b) {if (find(a) != find(b))f[find(a)] = find(b);
}bool cmp(road a, road b) {return a.v < b.v;
}void work() {cin >> n >> m;int a, b, c;for (int i = 1; i <= n; ++i) {f[i] = i;}int ans = 0;for (int i = 0; i < m; ++i) {cin >> arr[i].a >> arr[i].b >> arr[i].v;}sort(arr, arr + m, cmp);//先按路的权值排序,如果两点的祖先不是一个就加上然后合并。for (int i = 0; i < m; ++i) {if (find(arr[i].a) != find(arr[i].b)) {ans += arr[i].v;join(arr[i].a, arr[i].b);}}cout << ans << '\n';return 0;
}

正确性证明:

给一带权连通的树一定会有至少一棵生成树,那么这些生成树中间必然会会存在至少一棵最小生成树。

假设 T T T是用 k r u s k a l kruskal kruskal求出来的最小生成树,而 U U U是这个图的最小生成树,要证 U = T U = T U=T
然而如果 T ≠ U T \neq U T=U,那么至少存在一条边在 T T T中,不在 U U U中,假设存在 k k k条边存在 T T T中不存在 U U U中。
接下来进行 k k k次变换:
每次将在 T T T中不在 U U U中的最小的边 f f f拿出来放到 U U U中,那么 U U U中必然形成一条唯一的环路,我们取出这个环路上最小的且不在 T T T中的边 e e e放回到 T T T中,这样的边 e e e一定是存在的,因为之前的 T T T不存在环路(如果 e e e T T T中那么就可能和 f f f形成环路)。

在这里插入图片描述
现在证明 f f f e e e权值的关系:

假设 f < e f < e f<e,那么后来形成的 U U U是权值之和更小了,与 U U U是最小生成树矛盾。 实际上,不可能在 U U U中拿到大于 f f f的边,因为把 f f f拿走后,如果小于 f f f的边都不成立,至少 f f f是一个符合条件的边会被那回。

假设 f > e f > e f>e,那么根据 k r u s k a l kruskal kruskal的做法, e e e是在 f f f之前被取出来的边但是被舍弃了,一定是因为 e e e和比 e e e小的边形成了环路,而比 e e e小的边都是存在 U U U中的,而 e e e和这些边并没有形成环路,于假设矛盾。

于是 f f f一定和 e e e相等的, k k k次变换后, T T T U U U的权值之和是相等的。

最小生成树的值也是相等的。

复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)级别的,一般有mst就用这个。

int f[N];
struct road {int a, b, v;
} arr[N];
int tot = 0;int find(int a) {if (f[a] == a)  return a;return f[a] = find(f[a]);
}void join(int a, int b) {if (find(a) != find(b)) f[find(a)] = find(b);
}bool cmp(road a, road b) {return a.v < b.v;
}void work() {int a, b;cin >> a >> b;for (int i = 1; i <= b; ++i) {f[i] = i;arr[i] = {0, i, a};}tot = b;for (int i = 1; i <= b; ++i) {for (int j = 1; j <= b; ++j) {int x; cin >> x;if (x == 0) continue;else arr[++tot] = {i, j, x};}}ll ans = 0;sort(arr + 1, arr + 1 + tot, cmp);for (int i = 1; i <= tot; ++i) {if (find(arr[i].a) != find(arr[i].b)) {ans += arr[i].v;join(arr[i].a, arr[i].b);b--;}if (b == 0) break;}cout << ans << '\n';
}

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

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

相关文章

内容营销专家刘鑫炜:越是赚不到钱,越要加大推广力度

这两天&#xff0c;一位跟我们有长期合作关系的小微企业主老苏问我。 “现在钱这么不好赚&#xff0c;品牌推广应该怎么做&#xff1f;” 我说&#xff1a;“这是好机会&#xff0c;加大投放力度&#xff01;” 老苏很是不解&#xff0c;这时候不开源节流&#xff0c;还要加…

使用Git从Github上克隆仓库,修改并提交修改

前言 本次任务主要是进行github提交修改的操作练习实践&#xff0c;本文章是对实践过程以及遇到的问题进行的一个记录。 在此之前&#xff0c;我已经简单使用过github&#xff0c;Git之前已经下好了&#xff0c;所以就省略一些步骤。 步骤记录 注册github账号&#xff0c;gi…

【C++】C++指针在线程中调用与受保护内存空间读取方法

引言 在C的多线程编程中&#xff0c;正确地管理内存和同步访问是确保程序稳定性和安全性的关键。特别是当涉及到指针在线程中的调用时&#xff0c;对受保护内存空间的访问必须谨慎处理&#xff0c;以防止数据竞争、死锁和内存损坏等问题。本文将详细探讨C指针在线程中调用时如何…

易校网校园综合跑腿小程序源码修复运营版

简介&#xff1a; 易校网校园综合跑腿小程序源码修复运营版&#xff0c;带服务端客户端前端文档说明。 源码安装方法&#xff1a; 需要准备小程序服务号 服务器 备案域名 校园网跑腿小程序源码需要准备 1.小程序 2.服务器&#xff08;推荐配置2h4g3m&#xff09; 3.域名…

使用JMeter+Grafana+Influxdb搭建可视化性能测试监控平台

【背景说明】 使用jmeter进行性能测试时&#xff0c;工具自带的查看结果方式往往不够直观和明了&#xff0c;所以我们需要搭建一个可视化监控平台来完成结果监控&#xff0c;这里我们采用三种JMeterGrafanaInfluxdb的方法来完成平台搭建 【实现原理】 通过influxdb数据库存储…

开源模型应用落地-FastAPI-助力模型交互-WebSocket篇(五)

一、前言 使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。 FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,F…

SpringBoot中整合ONLYOFFICE在线编辑

SpringBoot整合OnlyOffice SpringBoot整合OnlyOffice实现在线编辑1. 搭建私有的OnlyOffice的服务2. SpringBoot进行交互2.1 环境2.2 我们的流程2.3 接口规划2.3.1 获取编辑器配置的接口2.3.2 文件下载地址2.3.3 文件下载地址 3. 总结4. 注意4.1 你的项目的地址一定一定要和only…

三层交换基础

一、什么是三层交换 三层交换是一种在OSI模型第三层&#xff0c;即网络层上工作的网络设备技术&#xff0c;它整合了二层交换机的功能和路由器的部分功能&#xff0c;以实现更高效的网络数据转发和路由选择。三层交换技术的核心在于结合了二层交换技术和三层转发技术&#xff…

【RabbitMQ实战】Springboot 整合RabbitMQ组件,多种编码示例,带你实践 看完这一篇就够了

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、对RabbitMQ管理界面深入了解1、在这个界面里面我们可以做些什么&#xff1f; 二、编码练习&#xff08;1&#xff09;使用direct exchange(直连型交换机)&a…

2024 年的 13 个 AI 趋势

2024 年的 13 个 AI 趋势 人工智能对环境的影响和平人工智能人工智能支持的问题解决和决策针对人工智能公司的诉讼2024 年美国总统大选与人工智能威胁人工智能、网络犯罪和社会工程威胁人工智能治疗孤独与对人工智能的情感依赖人工智能影响者中国争夺人工智能霸主地位人工智能…

【Lua小知识】Vscode中Emmylua插件大量报错的解决方法

起因 Vscode写Lua用的好好的&#xff0c;最近突然出现了大量报错。 看报错是有未定义的全局变量&#xff0c;这里查日志才发现是由于0.7.5版本新增诊断启用配置&#xff0c;所以导致了原先好的代码&#xff0c;现在出现了大量的报错。 解决方案一 最直接的方法当然是在配置中直…

用摄像头实现识别道路中的车道线、行人与车辆检测(级联分类器、HOG+SVM、行人检测)

基于树莓派的智能小车&#xff0c;用摄像头实现识别道路中的车道线识别、行人检测与车辆检测。 本项目旨在开发一套基于摄像头的智能道路环境感知系统&#xff0c;该系统能够实时识别道路中的车道线、行人与车辆&#xff0c;为自动驾驶汽车、智能交通管理以及辅助驾驶系统提供关…

LeetCode热题100刷题3:3. 无重复字符的最长子串、438. 找到字符串中所有字母异位词、560. 和为 K 的子数组

3. 无重复字符的最长子串 滑动窗口、双指针 class Solution { public:int lengthOfLongestSubstring(string s) {//滑动窗口试一下//英文字母、数字、符号、空格,ascii 一共包含128个字符vector<int> pos(128,-1);int ans 0;for(int i0,j0 ; i<s.size();i) {//s[i]…

python 中的生成器

目录 生成器示例基本生成器示例无限序列生成器使用生成器表达式实用示例&#xff1a;按行读取大文件生成器的 send、throw 和 close 方法 生成器和迭代器迭代器&#xff08;Iterator&#xff09;定义创建使用示例 生成器&#xff08;Generator&#xff09;定义创建使用示例 主要…

隐私计算实训营第二期第十课:基于SPU机器学习建模实践

隐私计算实训营第二期-第十课 第十课&#xff1a;基于SPU机器学习建模实践1 隐私保护机器学习背景1.1 机器学习中隐私保护的需求1.2 PPML提供的技术解决方案 2 SPU架构2.1 SPU前端2.2 SPU编译器2.3 SPU运行时2.4 SPU目标 3 密态训练与推理3.1 四个基本问题3.2 解决数据来源问题…

全新升级!中央集中式架构功能测试为新车型保驾护航

“软件定义汽车”新时代下&#xff0c;整车电气电气架构向中央-区域集中式发展已成为行业共识&#xff0c;车型架构的变革带来更复杂的整车功能定义、更多的新技术的应用&#xff08;如SOA服务化、智能配电等&#xff09;和更短的车型研发周期&#xff0c;对整车和新产品研发的…

OkHttp的源码解读1

介绍 OkHttp 是 Square 公司开源的一款高效的 HTTP 客户端&#xff0c;用于与服务器进行 HTTP 请求和响应。它具有高效的连接池、透明的 GZIP 压缩和响应缓存等功能&#xff0c;是 Android 开发中广泛使用的网络库。 本文将详细解读 OkHttp 的源码&#xff0c;包括其主要组件…

Qt实现手动切换多种布局

引言 之前写了一个手动切换多个布局的程序&#xff0c;下面来记录一下。 程序运行效果如下&#xff1a; 示例 需求 通过点击程序界面上不同的布局按钮&#xff0c;使主工作区呈现出不同的页面布局&#xff0c;多个布局之间可以通过点击不同布局按钮切换。支持的最多的窗口…

burpsuite 设置监听窗口 火狐利用插件快速切换代理状态

一、修改burpsuite监听端口 1、首先打开burpsuite&#xff0c;点击Proxy下的Options选项&#xff1a; 2、可以看到默认的监听端口为8080&#xff0c;首先选中我们想要修改的监听&#xff0c;点击Edit进行编辑 3、将端口改为9876&#xff0c;并保存 4、可以看到监听端口修改成功…

typescript学习回顾(五)

今天来分享一下ts的泛型&#xff0c;最后来做一个练习 泛型 有时候&#xff0c;我们在书写某些函数的时候&#xff0c;会丢失一些类型信息&#xff0c;比如我下面有一个例子&#xff0c;我想提取一个数组的某个索引之前的所有数据 function getArraySomeData(newArr, n:numb…