最小生成树

最小生成树之克鲁斯卡尔(Kruskal)算法

百般思念 提交于 2020-02-05 16:54:56
学习最小生成树算法之前我们先来了解下 下面这些概念: 树 (Tree):如果一个无向连通图中不存在回路,则这种图称为树。 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树。 生成树是连通图的极小连通子图。这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路;若去掉一条边,将会使之变成非连通图。 最小生成树 (Minimum Spanning Tree,MST):或者称为最小代价树Minimum-cost Spanning Tree:对无向连通图的生成树,各边的权值总和称为生成树的权,权最小的生成树称为最小生成树。 构成生成树的准则有三条: <1> 必须只使用该网络中的边来构造最小生成树。 <2> 必须使用且仅使用n-1条边来连接网络中的n个顶点 <3> 不能使用产生回路的边。 构造最小生成树的算法主要有:克鲁斯卡尔(Kruskal)算法和普利姆(Prim)算法他们都遵循以上准则。 接下分别讨论一下这两种算法以及判定最小生成树是否唯一的方法。 克鲁斯卡尔算法 克鲁斯卡尔算法的基本思想是以边为主导地位,始终选择当前可用(所选的边不能构成回路)的最小权植边。所以Kruskal算法的第一步是给所有的边按照从小到大的顺序排序。这一步可以直接使用库函数qsort或者sort。接下来从小到大依次考察每一条边(u,v)。

十八、最小生成树(克鲁斯卡尔算法)

匆匆过客 提交于 2020-02-05 16:54:41
最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树。 例如,对于如上图G4所示的连通网可以有多棵权值总和不相同的生成树。 克鲁斯卡尔算法介绍 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法。 基本思想 :按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路。 具体做法 :首先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止。 克鲁斯卡尔算法图解 以上图G4为例,来对克鲁斯卡尔进行演示(假设,用数组R保存最小生成树结果)。 第1步 :将边<E,F>加入R中。 边<E,F>的权值最小,因此将它加入到最小生成树结果R中。 第2步 :将边<C,D>加入R中。 上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。 第3步 :将边<D,E>加入R中。 上一步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。 第4步 :将边<B,F>加入R中。 上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>。将边<B,F>加入到最小生成树结果R中。 第5步 :将边<E,G>加入R中。

2019 GDUT 新生专题Ⅲ E题

你说的曾经没有我的故事 提交于 2020-02-05 03:56:51
E - Arctic Network 国防部(DND)希望通过无线网络连接几个北方前哨。在建立网络时,将使用两种不同的通信技术:每个前哨站将有一个无线电收发机,一些前哨站还将有一个卫星频道。 任何两个有卫星信道的前哨站都可以通过卫星进行通信,而不管它们的位置如何。否则,只有当两个前哨站之间的距离不超过D时,它们才能通过无线电进行通信,这取决于收发器的功率。更高的功率产生更高的D,但成本更高。出于购买和维护的考虑,前哨站的收发器必须是相同的;也就是说,每对前哨站的D值都是相同的。 您的工作是确定收发器所需的最小D。每对前哨站之间必须至少有一条通信路径(直接或间接)。 输入 输入的第一行包含N,测试用例的数量。每个测试用例的第一行包含1<=S<=100(卫星信道数)和S<P<=500(前哨站数)。随后是P线,给出每个前哨的(x,y)坐标(单位:km)(坐标是0到10000之间的整数)。 输出 对于每种情况,输出应包括给出连接网络所需的最小D。输出应指定为2个小数点 Sample Input 1 2 4 0 100 0 300 0 600 150 750 Sample Output 212.13 思路:首先题目要求每个点都能够联通,所以可以先建立一个最小生成树,然后根据题目里卫星信道的作用,两个信道之间可以形成一条道路,并且不受距离影响。 比如1.给出有两个卫星通道,即s=2

求最小生成树-Prim算法和Kruskal算法解析及代码实现

限于喜欢 提交于 2020-02-04 00:19:29
由于数据结构学过一段时间了,有些知识点有点遗忘,所以先来复习一下一些知识点: 什么是最小生成树? 最小生成树是在一个给定的 无向图 G中求一棵树T,使得这棵树拥有图G中的所有顶点,且所有边都是来自图G中的边,并且满足整棵树的边权之和最小。 最小生成树的三个性质: 1,最小生成树是树,因此其边数等于顶点数减1,且树内一定不会有环。 2,对于给定的图G,其最小生成树可以不唯一,但其边权之和一定是唯一的 3,由于最小生成树是在无向图上生成的,因此其根结点可以实这棵树上的任意一个结点。 求最小生成树一般有两种算法,即prim和kruskal。这两种算法都是采用了贪心的思想,只是贪心的策略不太一样。 Prim算法:(普里姆算法) 用来解决最小生成树问题,其基本思想是对图G(V,E)设置集合S,存放已被访问的顶点,然后每次从集合V-S中选择与集合S的最短距离最小的一个顶点(记为 u),访问并加入集合S。之后,令顶点u为中介点,优化所有从u能到达的顶点v 与集合S之间的最短距离。这样的操作执行n次(n为顶点个数),直到集合S已包含所有的顶点。可以发现,prim算法的思想与最短路径中的Dijkstra算法的思想几乎完全相同,只是在涉及最短距离时使用了集合S代替Dijkstra算法中的起点s。 Kruskal算法:(克鲁斯卡尔算法) 同样是用来解决最小生成树问题的一个算法。和prim算法不同

LibreOJ #10067 构造完全图(由最小生成树构造最小完全图)

折月煮酒 提交于 2020-02-03 01:58:16
题目链接 : https://loj.ac/problem/10067 完全图 : 若一个图的每一对不同顶点恰有一条边相连,则称为完全图。 完全图是每对顶点之间都恰连有一条边的简单图。n个端点的完全图有n个端点及n(n − 1) / 2条边。由 最小生成树复原最小完全图 : 最小生成树T,T中的每一条边都是一条 割边 去掉任意一条树T中的边,这个树一定会变成 两个联通块 ,令其为A、B。 要将T扩展为完全图G,那么显然 A中的每个点都需要与B中的所有点相连 。 A中新发出的连边的权值一定是 大于 (若等于则存在多种最小生成树解,不合题意) 出发点在树上的相接边的权值 的。 再一看数据量,单独枚举肯定不行。由联通块可以联想到并查集,发现可行。 对于一条最小生成树上的边E<A,B>,可以看做E连接了A,B两个联通块。 那么要将A、B两块连接为一个完全图需要加的边数就是 cnt[A] * cnt[B]-1,其中 cnt表示联通块中的结点个数 。 边的权值一定是大于E的权值的,要使其最小,那么这些边的权值都是 E的权值+1 那么合并A、B两个联通块的花费就是 (边E.权+1)*(cnt[A]*cnt[B]-1)。ans在每次合并联通块时加上花费即可求解。 另外一点,因为要求的是最小的完全图,所以有一个贪心策略:先把树上的边按照 权值从小到大排序 ,然后枚举即可。 代码 : #include

算法 - 最小生成树

China☆狼群 提交于 2020-02-02 00:36:08
什么是最小生成树 ​ 一个有 n 个结点的 连通图 的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用 kruskal (克鲁斯卡尔)算法或 prim (普里姆)算法求出。 最小权重生成树又是什么 ​ 在一给定的 无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此 边 的权重,若存在 T 为 E 的 子集 (即)且为无循环图,使得 的 w(T) 最小,则此 T 为 G 的 最小生成树 。 最小生成树其实是 最小权重生成树 的简称。 实际应用场景 例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。 算法实现 我们首先看我们的无向图 , 需要找到一个最小权重生成树 kruskal 算法 其基本思想就是把每条边都拿出来, 然后按照权重排序, 将这些边组合起来, 要求的是组合过程中不可以形成环, 形成环则放弃这条边 基本实现就是这个了, 打错的是不符合要求的. 到最后就会形成最小权重生成树 Prim 算法 其基本思想就比较麻烦, 我们先看一张图 这里有四行数据, 第一行各个节点. 第二行是节点是否被选中

【模板】Prim

心已入冬 提交于 2020-01-31 21:39:31
Prim算法 给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。 求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。 给定一张边带权的无向图G=(V, E),其中V表示图中点的集合,E表示图中边的集合,n=|V|,m=|E|。 由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。 输入格式 第一行包含两个整数n和m。 接下来m行,每行包含三个整数u,v,w,表示点u和点v之间存在一条权值为w的边。 输出格式 共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。 数据范围 1≤n≤500, 1≤m≤105, 图中涉及边的边权的绝对值均不超过10000。 输入样例: 4 5 1 2 1 1 3 2 1 4 3 2 3 2 3 4 4 输出样例: 6 Prim 时间复杂度:O(nm) 空间复杂度:nm 用处:求最小生成树 Prim算法与 Dijkstra 非常相近,我推荐先读这篇文章: 【模板】Dijkstra 好了,既然十分相似,那我们就上代码: # include <bits/stdc++.h> using namespace std ; const int N = 510 , INF =

畅通工程再续

心不动则不痛 提交于 2020-01-31 04:34:57
不贴题目了 这个题太有意思了!!! 没想到最小生成树的题还能这么搞 竟然一个是托 最后又到最小生成树的经典做法上了 第一次没对 我又仔细看了看题 原来这个也是最小权重啊 我一开始根本没考虑最小的问题 只是把不在一块的岛 连了起来 后来又改了几次 样例都对 我觉得也没啥毛病 但 啊 就是不对 后来我又从CSDN上搜了 那个作者说的让我突然又思路了: 需要往模板方向靠拢,在要求的条件之下,化为: 村1 村2 距离/价钱 不就是把他们两个两个的遍历一遍吗 然后记下他们的编号 和他们之间的距离 就成了经典的最小生成树的问题了 // 这个题太有意思了!!! // 没想到最小生成树的题还能这么搞 // 竟然一个是托 最后又到最小生成树的经典做法上了 // 第一次没对 我又仔细看了看题 原来这个也是最小权重啊 我一开始根本没考虑最小的问题 // 只是把不在一块的岛 连了起来 // 后来又改了几次 样例都对 我觉得也没啥毛病 但 啊 就是不对 // 后来我又从CSDN上搜了 // 那个作者说的让我突然又思路了: // 需要往模板方向靠拢,在要求的条件之下,化为: 村1 村2 距离/价钱 // 不就是把他们两个两个的遍历一遍吗 然后记下他们的编号 和他们之间的距离 // 就成了经典的最小生成树的问题了 # include <iostream> # include <vector> # include

最小生成树

北战南征 提交于 2020-01-30 22:00:36
给定边权为正的连通图G,找出连接所有顶点的边的最小权值(集)。 Kruskal : 步骤: 1. 按边权从小到大的顺序遍历边。 2. 如果边对应的两个点不在同一连通分量中,则将其相连。否则忽略。 贪心 + 并查集,时间复杂度$O(ElogE+E*A(V)+V)(A\ is\ Ackermann)$。 Prim : 步骤: 1. S = {x}(x为任意点)。 2. 重复以下操作直到S中有V个点。 设E是只有一个端点在S的边中的最小边。 将另一个端点加入S。 贪心 + 优先级队列,时间复杂度$O((E+V)log(V))$。 例题:洛谷P3366 https://www.luogu.com.cn/problem/P3366 1. Kruskal #include<bits/stdc++.h> using namespace std; const int N = 200010; int n, m, w[N], u[N], v[N], f[5010], o[N]; int cmp(int a, int b) {return w[a] < w[b];} int find(int k) {return f[k] == k ? k : f[k] = find(f[k]);} int Kruskal() { int ans = 0; for(int i = 0; i < n; i++) f[i]

D. 0-1 MST

落花浮王杯 提交于 2020-01-30 21:43:16
题意:给定一张完全图,即每个点都跟另一个点相连,然后有n个点,编号为1到n,然后有m条边的权值为1,其它边全为0,求最小生成树。 分析:使用最小生成树算法不行,因为时间复杂度太高了,每个点都和另一个点相连,大概有n * (n - 1) / 2条边,超时。我们可以采样另一种做法,我们将所有边权为0且相连的点看成一个联通块,每个联通块和其它联通块通过一条或多条边权为1的边相连,那么我们把这些联通块看成一个点,即 缩点 ,那么我们就在新图上求最小生成树,那么这个最小生成树的答案就是联通块的个数-1,(树的性质:边数等于顶点数减一),可以画个图,因为每个点和其它所有点相连,有0和1的边,那么我们把所有边权为0且相连的点看成一个联通块,这个联通块通过很多1的边和其它连通块相连,我们只需要选择一条,就可以和其它连通块相连,其它权值为1的点都可以省去,那么就可以得到一个最小生成树。 #include <iostream> #include <cstdio> #include <cstring> #include <set> #include <vector> #include <algorithm> using namespace std; const int N = 100005; set<int> k; set<int> g[N]; bool st[N]; int n, m; void