热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

图——最小生成树——kruskal算法

1.最小生成树1.1.kruskal算法kruskal算法,就是一个贪心的思想。从小到大,加入符合条件的边。1.1.1.步骤新建图G,

1. 最小生成树


1.1. kruskal算法


kruskal算法,就是一个贪心的思想。从小到大, 加入符合条件的边。



1.1.1. 步骤


  1. 新建图G, G中拥有原图中相同的节点, 但没有边
  2. 将原图中所有的边按权值从小到大排序
  3. 从权值最小的边开始,如果这条边连接的两个节点于图G中不同一个连通分量中, 则添加这条边到图G中。
  4. 重复3,直至图G中所有的节点都在同一个连通分量中

1.1.2. 证明


  1. 这样的步骤保证了选取的每条边都是桥,因此图G构成一个树。
  2. 为什么这一定是最小生成树呢?关键还是步骤3中对边的选取。算法中总共选取了n-1条边,每条边在选取的当时,都是连接两个不同的连通分量的权值最小的边
  3. 要证明这条边一定属于最小生成树,可以用反证法:如果这条边不在最小生成树中,它连接的两个连通分量最终还是要连起来的,通过其他的连法,那么另一种连法与这条边一定构成了环,而环中一定有一条权值大于这条边的边,用这条边将其替换掉,图仍旧保持连通,但总权值减小了。也就是说,如果不选取这条边,最后构成的生成树的总权值一定不会是最小的。

1.1.3. 时间复杂度

平均时间复杂度为O(|E|log|V|),其中EV分别是图的边集和点集。


1.1.4. 伪代码

KRUSKAL-FUNCTION(G, w)
1 F := 空集合//起初每个顶点为一棵只有一个节点的树。
2 for each 图 G 中的顶点 v
3 do 将 v 加入森林 F
4 所有的边(u, v) ∈ E依权重 w 递增排序
5 for each 边(u, v) ∈ E
6 do if u 和 v 不在同一棵子树
7 then F := F ∪ {(u, v)}
8 将 u 和 v 所在的子树合并

1.1.5. CPP模板

对于1.1.2中的第三步,我们可以通过并查集来确定一条边的两个端点是否在同一个连通分量。

const int MAXN = 110;//最大点数
const int MAXNM = 1e4; //最大边数struct Edge{int u;//端点1int v;//端点2int w;//权值
};
//边集数组
vector<Edge>edge;//并查集&#xff1a;并查集使用
int par[MAXN];//并查集&#xff1a;初始化操作
void makeSet(){for(int i &#61; 0;i < MAXN;i&#43;&#43;)par[i] &#61; i;
}//并查集: 查找节点的根.
int Find(int x){if(par[x] &#61;&#61; x)return par[x];else return par[x] &#61; Find(par[x]);
}//并查集&#xff1a;合并两个节点
void Union(int x, int y){int rootx &#61; Find(x);int rooty &#61; Find(y);if(rootx !&#61; rooty)par[rootx] &#61; rooty;
}//排序函数
bool cmp(Edge a, Edge b){return a.w < b.w;
}int Kruskal(int n){makeSet();int cnt&#61;0; //计算加入的边数int ans &#61; 0;//1.排序sort(edge.begin(),edge.end(), cmp); /**2.从权值最小的边开始&#xff0c;如果这条边连接的两个节点于图G中不同一个连通分量中&#xff0c; 则添加这条边到图G中。**/for(int i &#61; 0;i < edge.size();i&#43;&#43;){int u &#61; edge[i].u;int v &#61; edge[i].v;int w &#61; edge[i].w;if(Find(u)!&#61; Find(v)){Union(u, v);ans&#43;&#61;w;cnt&#43;&#43;;}if(cnt &#61;&#61; n - 1)break;}if(cnt < n-1) return -1; //不连通&#xff0c;不能产生最小生成树else return ans;
}

参考


  1. kuangbin板子
  2. 维基百科克鲁斯克尔算法
  3. OI-WiKi

推荐阅读
  • 函子(Functor)是函数式编程中的一个重要概念,它不仅是一个特殊的容器,还提供了一种优雅的方式来处理值和函数。本文将详细介绍函子的基本概念及其在函数式编程中的应用,包括如何通过函子控制副作用、处理异常以及进行异步操作。 ... [详细]
  • 使用Matlab创建动态GIF动画
    动态GIF图可以有效增强数据表达的直观性和吸引力。本文将详细介绍如何利用Matlab软件生成动态GIF图,涵盖基本代码实现与高级应用技巧。 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • 本文详细探讨了Java中HashMap类的hash()方法的工作原理及其重要性,特别是在JDK 7版本中的实现。 ... [详细]
  • 贡献转移在计算每个元素的作用的时候,我们可以通过反向枚举作用效果,添加到作用元素的身上,这种方法叫做贡献转移。更正式的说, ... [详细]
  • 探讨了一个包含纯虚函数的C++代码片段,分析了其中的语法错误及逻辑问题,并提出了修正方案。 ... [详细]
  • 利用Node.js实现PSD文件的高效切图
    本文介绍了如何通过Node.js及其psd2json模块,快速实现PSD文件的自动化切图过程,以适应项目中频繁的界面更新需求。此方法不仅提高了工作效率,还简化了从设计稿到实际应用的转换流程。 ... [详细]
  • 深入解析C语言中的关键字及其分类
    本文将全面介绍C语言中的关键字,并按照功能将其分为数据类型关键字、控制结构关键字、存储类别关键字和其他关键字四大类,旨在帮助读者更好地理解和运用这些基本元素。C语言中共有32个关键字。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 本文深入探讨了Go语言中的接口型函数,通过实例分析其灵活性和强大功能,帮助开发者更好地理解和运用这一特性。 ... [详细]
  • 3.[15]Writeaprogramtolistallofthekeysandvaluesin%ENV.PrinttheresultsintwocolumnsinASCIIbet ... [详细]
  • 解决Visual Studio Code中PHP Intelephense误报问题
    PHP作为一种高度灵活的编程语言,其代码结构可能导致Intelephense插件在某些情况下报告不必要的错误或警告。自1.3.3版本起,Intelephense引入了多个配置选项,允许用户根据具体的工作环境和编程风格调整这些诊断信息的显示。 ... [详细]
  • linux网络子系统分析(二)—— 协议栈分层框架的建立
    目录一、综述二、INET的初始化2.1INET接口注册2.2抽象实体的建立2.3代码细节分析2.3.1socket参数三、其他协议3.1PF_PACKET3.2P ... [详细]
author-avatar
wuke85394
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有