kruskal算法

[算法系列之二十七]Kruskal最小生成树算法

我只是一个虾纸丫 提交于 2019-12-17 08:01:16
简介 求最小生成树一共有两种算法,一个是就是本文所说的Kruskal算法,另一个就是Prime算法。在详细讲解Kruskal最小生成树算法之前,让我们先回顾一下什么是最小生成树。 我们有一个带权值的图,我们要求找到一个所有生成树中具有最小权值的生成树。如下图所示,T是图G的生成树。但不是具有最小权值的生成树。 我们可以把他们想象成一组岛屿和连接它们的可能的桥梁。当然修桥是非常昂贵和费时的,所以我们必须要知道建设什么样的桥梁去连接各个岛。不过有一个重要的问题,建设这样一组连接所有岛屿的桥梁的最低价格是多少。 我们实际上需要构建一棵最小生成树,顶点表示岛屿,而边表示它们之间可能要修建的桥梁。每一个可能修建的桥梁都有相应的权值(表示我们建造它所花费的时间和金钱等)。 在实践中,我们只可能使用一个最小生成树的可能用例。(This scenario is only one of possible use cases of where minimum spanning trees can be used in practice.) 概要 Kruskal算法开始由初始化一组集合,并建立| V|棵树,每棵树都只包含了图的一个顶点。 在建设最后生成树的过程中,我们维护一个森林。很显然,我们由|V|棵树组成的森林开始,其中每个树都只有是一个节点。 在某些时候,我们有“K”棵树组成的森林

日日算法:Kruskal算法

孤人 提交于 2019-12-04 06:49:49
介绍 克鲁斯卡尔(Kruskal)算法是用来求出连通图中最小生成树的算法。 连通图:指==无向图==中==任意两点都能相通==的图。 最小生成树:指联通图的所有生成树中==边权重的总和最小==的树(即,找出一个树,让其联通所有的点,并让树的边权和为最小)。 算法思想 克鲁斯卡尔算法的主要基本思想有两点原则: 按照从小到大的顺序选择边,并将边的两端连线,构成新的图 保证新加入的边不能在新的图上形成环 重复以上步骤,直至添加 n-1 条边 用图表示该算法的解体过程: 算法证明 我是通过反证的方式理解该算法的。 证明按上述算法添加 n-1 条边时,一定能连通 n 个节点。 证明: Kruskal 算法保证了针对 n 个节点,它添加了 n-1 条边,且不存在环。那么假设这 n-1 条边没有全部连通 n 个节点。也就说至少有1个点没有边,那么至多只有 n-1 个点使用 n-1 条边,当 n-1 个点使用 n-1 条边时,必定构成环。与要求不符,故反正成立。 证明新的图中再添加一条边,一定构成环。 步骤一证明了新生成的图一定是一个连通图,也就是任意两点之间必定已经相连,当我们在加入一条新的边的时候,边两段的点又多了一条新相连的路,因此构成了环。 证明在构成新的环中,新加入的边一定是最长的边。 假设新加入的边,并非是环中最大的边,那么可以去掉这个环中最大的边,且剩下的边不够环

[总结]最小生成树之Kruskal算法

前提是你 提交于 2019-12-03 17:04:28
目录 一、最小生成树的相关知识 1. 树的性质 2. 生成树 3. 最小生成树 4. 最小生成树的性质 二、Kruskal算法求最小生成树 1. 核心思想 2. 具体流程 3. 代码实施 三、例题 例1: P2212 [USACO14MAR]浇地Watering the Fields 例2: P1550 [USACO08OCT]打井Watering Hole 例3: P1547 Out of Hay 例4: P1340 兽径管理 一、最小生成树的相关知识 1. 树的性质 树实际上是图的特殊形态, 对于任意一张无向连通图 \(G=(V,E)\) ,其中 \(n=|V|,m=|E|\) 。 该图为树时的性质: |E|=|V|-1 图中无环 图连通 任意两点有且仅有一条简单路径 删除任意一条边后该图不连通 2. 生成树 在一个有 \(|V|\) 个点的无向连通图中,取其中 \(|V|-1\) 条边,并连接所有的顶点,所得到的子图为原图的生成树(Spanning Tree)。 3. 最小生成树 在一个带权无向连通图中,各边权和最小的一棵生成树即为原图的最小生成树(Minimum Spanning Tree,MST)。 4. 最小生成树的性质 1. 最小边原则: 图中权值最小的边(唯一)一定在最小生成树上。 2.唯一性定理: 对于一个图 \(G\) ,如果图中边权都不相同

Kruskal算法(最小生成树)

匿名 (未验证) 提交于 2019-12-02 23:05:13
Kruskal算法:首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值最小的边且不会产生回路的边加入到生成树中,直到加入n-1条边就结束; 算法难点在与如何判断是否会产生回路。这个可以通过并查集实现,将所有加入生成树的结点加入同一个集合; 代码: #include <string.h> #include<iostream> #include<vector> #include<queue> #include <algorithm> using namespace std; struct edge{//边的结构 int u; int v; int w; }e[100]; int f[100];//并查集数组 bool compare(struct edge a,struct edge b){//sort函数的比较器,实现边权从小到达排序 return a.w<=b.w; } int getF(int x){//查找结点的根 if(f[x]==x) return x; else { f[x]=getF(f[x]);//直接连接到根结点,实现路径压缩 return f[x]; } } bool unity(int a,int b){//联合所有加入生成树的结点 int f1=getF(a); int f2=getF(b); if(f1!=f2){ f[f1]=f2; return

Kruskal算法

梦想与她 提交于 2019-12-01 07:08:49
Kruskal算法的时间复杂度为O(ElogE)E为边数 Kruskal算法是基于贪心的思想得到的。 首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边, 如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。 至于怎么合并到一个集合,那么这里我们就可以用到一个工具——-并查集 换而言之,Kruskal算法就是基于并查集的贪心算法 即: 输入: 图G 输出: 图G的最小生成树 具体流程: (1)将图G看做一个森林,每个顶点为一棵独立的树 (2)将所有的边加入集合S,即一开始S = E (3)从S中拿出一条最短的边(u,v),如果(u,v)不在同一棵树内,则连接u,v合并这两棵树,同时将(u,v)加入生成树的边集E’ (4)重复(3)直到所有点属于同一棵树,边集E’就是一棵最小生成树 1 int n,m,ans; 2 int f[5005]; 3 struct bian{ 4 int x,y,z; 5 }a[200009]; 6 bool cmp(bian x,bian y){return x.z<y.z;} 7 int F(int x) 8 { 9 if(x!=f[x]) return f[x]=F(f[x]); 10 return x; 11 } 12 int main() 13 { 14 scanf("%d%d",&n,&m);

Kruskal算法 (克鲁斯卡尔)

≡放荡痞女 提交于 2019-11-30 08:36:22
定义 Kruskal算法是一种用来查找最小生成树的算法。 准备 树: 如果一个无向连通图中不存在回路,则这种图称为树。 生成树 : 无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树。 生成树是连通图的极小连通子图。这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路;若去掉一条边,将会使之变成非连通图。 最小生成树: 对无向连通图的生成树,各边的权值总和称为生成树的权,权最小的生成树称为最小生成树。 构成生成树的准则有三条: ① 必须只使用该网络中的边来构造最小生成树。 ② 必须使用且仅使用n-1条边来连接网络中的n个顶点 ③ 不能使用产生回路的边。 实现 ① 将原图中每条边的权值进行从小到大排序。 ② 从小到大依次判断每条边。 若当前边不会与当前的最小生成树形成回路,则将当前边加入当前的最小生成树。 反之,则放弃该边,继续判断下一条边。 直到选择了(顶点数-1)条边为止,此时的生成树为最小生成树。(一般利用并查集判断是否形成回路) ① 排序 ②从小到大判断每条边。 代码 #include<bits/stdc++.h> using namespace std; struct node { int u,v,w; node(){} node(int a,int b,int c) {u=a;v=b;w=c;} bool operator <(const

Kruskal算法

拜拜、爱过 提交于 2019-11-29 10:20:05
步骤: 新建图G,G中拥有原图中相同的节点,但没有边 将原图中所有的边按权值从小到大排序 从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中,则添加这条边到图G中 重复3,直至图G中所有的节点都在同一个连通分量中 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 struct node{ 6 int x,y,w; 7 }a[200002]; 8 9 int f[200002]; 10 11 bool cmp(node xx,node yy){//结构体排序 12 return xx.w<yy.w; 13 } 14 15 int find(int x){ 16 //并查集说白了就是找父结点的过程,同一个父节点即同一个区间 17 if(x==f[x]) return x; 18 f[x]=find(f[x]); 19 return f[x]; 20 } 21 22 int main(){ 23 int n,k,m=0; 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++){ 26 f[i]=i; 27 for(int j=1;j<=n;j++) 28 { 29 scanf("%d",&k); 30 if(j>i){ 31 //读入时加一个判断就可以了,不需要读那么多 32

Kruskal算法求最小生成树 笔记与思路整理

两盒软妹~` 提交于 2019-11-28 07:56:33
整理一下前一段时间的最小生成树的算法。 (其实是刚弄明白 Kruskal其实算是一种贪心算法。先将边按权值排序,每次选一条没选过的权值最小边加入树,若加入后成环就跳过。 先贴张图做个示例。 (可视化均来自VisuAlgo) 1、邻接链表: Edge From To Val 1 0 1 9 2 0 2 75 3 1 2 95 4 1 3 19 5 2 3 51 6 1 4 42 7 3 4 31                   2、按权值排序(可以直接写个cmp,sort()结构体): Edge From To Val 1 0 1 9 4 1 3 19 7 3 4 31 6 1 4 42 5 2 3 51 2 0 2 75 3 1 2 95 3、依次选边,若成环则跳过,否则加入最小生成树并计数。   这里判断是否成环用的是并查集:如果新加入的边两个端点在同一个集合中,就说明已经有一条路径联通这两个端点。 4、重复3,直到加入了n-1条边或遍历完成(无最小生成树)。 选取1号、4号、7号后: 选取6号(1--4),成环,跳过; 加入5号(2--3),达到n-1条,最小生成树形成。 代码实现晚上再写。 来源: https://www.cnblogs.com/miserweyte/p/11400549.html

Kruskal克鲁斯卡尔算法

非 Y 不嫁゛ 提交于 2019-11-27 19:35:39
克鲁斯卡尔算法依靠两个辅助数组parent[ ] 和edges[ ]. parent[]数组用于实现并查集操作,即查询一个顶点所在集合的根节点,以及将两个集合合并成为一个集合。 edges[]数组作为图中边的集合,其中各个边按照权值大小升序排序,这样克鲁斯卡尔算法只需依次遍历edges[]数组便可依次向树中 添加一个当前权值最小的边,另外借助parent[]数组的查询操作保证加入的边不会造成环。 1 #define MAXSIZE 100; 2 typedef struct{ 3 int a; //a,b为边的两个顶点 4 int b; 5 int weight; //这条边的权值 6 }Edge; //边结构体 7 8 int find(* parent,int a) //查找顶点a的所在集合的根结点 9 { 10 while(parent[a] > 0) //paren数组中根节点的值等于-1 11 a = parent[a]; 12 return a; 13 } 14 int parent[MAXSIZE]; //父亲顶点数组 实现并查集操作 15 Edge edges[MaxEdge]; //边数组 16 17 void Kruskal(MGrahp G) 18 { 19 int i,a,b; 20 sort(deges); //对图中的边按权值大小升序排列 21 for

C++ Kruskal算法

拈花ヽ惹草 提交于 2019-11-27 14:33:18
kruskal与prim都是用于图的最小生成树,prim从点出发,kruskal从边出发,不同的角度解决问题,对应不同的应用场景。prim适用于点少边多的图(稠密图),kruskal 使用于边少点多的图(稀疏图),中心思想就是先排序所有边,从最小寻找两点对应的根,再把根相连,若根相同,则会成环,这在树中是不被允许的。树中的边的数目为点的数目-1,则完成最小生成树。以下代码用邻接矩阵实现,用邻接表更容易实现,我就不打邻接表的实现了,很简单 #include<iostream> #define MAX_VERTEX 100 #define INFINITE 65535 using namespace std; //common int _count=0; struct Side{ int start; int end; int weight; }; Side* _pSide; int vertex_parent[MAX_VERTEX]; int GetParent(int i){ int k=vertex_parent[i]; while(k!=0){ i=k; k=vertex_parent[k]; } return i; } //array char vertex_infos[MAX_VERTEX]; int matrix[MAX_VERTEX][MAX_VERTEX]; void