最小生成树

【ACM算法】-- 图论篇 - 最小生成树(MST)

青春壹個敷衍的年華 提交于 2020-03-03 00:20:32
第一题: 这里讨论最小生成树问题,最小生成树是原图的一个子图,其中包含所有节点,仅含有部分边,使得这个子图为连通图,且不含有环路,并且边上的权值和最小,则称为最小生成树。 思路: 这道题用克鲁斯卡尔的方法来求最小生成树: 如上图:我们需要两种数据结构,一个是用来确定两个点是否属于一个集合,另一个是我们要将边的权值进行排序,需要一个struct来存储边,并且用到了重载小于号,使用sort快排。 代码如下: # include <stdio.h> # include <algorithm> using namespace std ; # define N 101 int Tree [ N ] ; int findRoot ( int x ) { if ( Tree [ x ] == - 1 ) return x ; else { int tmp = findRoot ( Tree [ x ] ) ; Tree [ x ] = tmp ; return tmp ; } } struct Edge { int a , b ; int cost ; bool operator < ( const Edge & A ) const { return cost < A . cost ; } } edge [ 6000 ] ; int main ( ) { int n ; freopen (

最小生成树的建模+POJ - 1789Truck History

心不动则不痛 提交于 2020-03-02 10:43:05
Truck History Description: 给定N个字符串,每个字符串都继承于另一个字符串(除了祖先字符串),某个字符串转为另一个字符串的花费为他们每一位不相同的字符数。 求最小花费Q。 字符串与字符串之间的关系正是点与点之间的关系,每一位不相同的字符数就是边权,最终每个点都要有父节点(树的连通性),不能多继承(无环性)。 注意: 不要用c++的cin输入流,和string,速度太慢了以至于TLE . # include <stdio.h> # include <iostream> # include <cmath> # include <math.h> # include <string> # include <string.h> # include <algorithm> # define ll long long using namespace std ; const int maxn = 2005 ; //数组要开够 int n , m , fa [ maxn ] ; char dots [ 2005 ] [ 10 ] ; struct Edge { int u , v , cost ; } t [ maxn * maxn ] ; int get_cost ( int x , int y ) { int sum = 0 ; for ( int i = 0 ; i

【图论】最小生成树算法(prim和kruskal详解及对比)

心已入冬 提交于 2020-03-02 10:32:06
目录 一.最小生成树之 p r i m prim p r i m 算法 p r i m prim p r i m 完整代码(计算最短距离并输出路径) 堆优化版本 二.最小生成树之 k r u s k a l kruskal k r u s k a l 算法 k r u s k a l kruskal k r u s k a l 完整代码(计算最短距离并输出路径) 三. p r i m prim p r i m 和 k r u s k a l kruskal k r u s k a l 相对比 1. 1. 1 . 时间上 2. 2. 2 . 空间上 3. 3. 3 . USACO07DEC道路建设 B u i l d i n g R o a d s Building Roads B u i l d i n g R o a d s ( p r i m prim p r i m 算法+堆优化与 K r u s k a l Kruskal K r u s k a l +路径压缩对比) 一.最小生成树之 p r i m prim p r i m 算法 Prim算法适用于稠密图 Kruskal适用于稀疏图 M S T MST M S T ( M i n i m u m S p a n n i n g T r e e Minimum Spanning Tree M i n i m u m S p

算法分析与设计 MST kruskal

爷,独闯天下 提交于 2020-03-01 12:01:02
算法分析与设计 最小生成树 kruskal算法 问题描述: 一个带权连通图,其中顶点集合为V,边集合为E,任选一些点∈V,边∈E,这些点,边构成的新图连通性不变并且边权最小。 下面是百度百科给出的描述: 在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得 的 w(T) 最小,则此 T 为 G 的最小生成树。 算法思路: kruskal: 假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。 具体步骤可以参照下面的样例 假设有m条边,将所给出的m条边的权值从小到大排序,从小的边开始建树,如果这条边的两端定点没有处于一棵树中,那么就将这两端顶点的树合并。否则就跳过这条边

最小生成树学习笔记

百般思念 提交于 2020-03-01 07:03:03
1. 题意: 这里 解法:这道题需要知道欧拉路径。显然整张图奇度点<=2的时候我们只计算一次就OK了。但对于绝大多数情况,我们要想办法构造一条欧拉路径,这样的话,每条边走的次数<=2,但是每条边走的次数至少为1。如果要构造两个点从奇度边偶度,我们需要把他们之间的一条路径重复添加一次,这样才能满足。题目第i条边权为2^i次方,也就是说前i-1条边相加的权值依旧没有第i条边的权值大,那么我们尽可能添加小边权,怎么做呢?如果在最小生成树上做就很方便了,写法依旧可以看这篇博客,没有提交链接qaq我就没写了。 来源: CSDN 作者: Alex Panda 链接: https://blog.csdn.net/weixin_43262291/article/details/104573948

Kruskal算法构造最小生成树

孤人 提交于 2020-03-01 01:25:32
问题[描述算法问题,首选形式化方式(数学语言),其次才是非形式化方式(日常语言)] 在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无向循环图,使得的 sum(w(u, v))最小,则此 T 为 G 的最小生成树。 解析[问题的理解和推导,可用电子版直接在此编写,也可用纸笔推导,拍照嵌入本文档] 设计[核心伪代码] 首先运用快排把边按升序分别排列好,然后再开始KRUSKAL函数 void kruskal(Edge E[],int n,int e){ 定义一个初始数组 k表示当前最小生成树边的总数 j表示E里边的下标,默认初值为0 当生成的边数小于总边长的时候继续循环 { m1=E[j].vex1; m2=E[j].vex2;//取一条边的两个邻接点 sn1=vset[m1]; sn2=vset[m2]; //分别得到两个顶点所属的集合编号 if(sn1!=sn2)//两顶点分属于不同的集合,该边是最小生成树的一条边 { 输出两个顶点和所在边 总和相加 生成的最小生成树边数增加1 如果边有达到最大的数量 退出循环 for(i=1;i<=n;i++) 两个集合统一起来集合编号修改 } 继续下一条边 } 最后输出总和} 4. 分析[算法复杂度推导]时间复杂度

[转]图论题集

假如想象 提交于 2020-02-29 20:23:55
========以下是最小生成树+并查集========== HDU 1213 基础并查集★ HDU 1272 基础并查集★ HDU 1325 Tree? HDU 1856 基础并查集★ HDU 1102 基础最小生成树★ HDU 1232 基础并查集★ HDU 1233 基础最小生成树★ HDU 1863 基础最小生成树★ HDU 1875 基础最小生成树★ HDU 1879 基础最小生成树★ HDU 3371 简单最小生成树★ HDU 1301 基础最小生成树★ HDU 1162 基础最小生成树★ HDU 1198 基础最小生成树★ HDU 1598 HDU 1811 并查集+拓扑排序★★ HDU 3926 同构图★ HDU 3938 离线+并查集★★ HDU 2489 dfs枚举组合情况+最小生成树★ HDU 4081 National HDU 4126 Conqueror HDU 1829 基础种类并查集★ HDU 1558 计算几何+并查集★ HDU 3461 并查集(有点难想到)★★ HDU 3367 最大生成树★ HDU 2473 并查集+设立虚父节点(马甲)★★ HDU 3172 带权并查集★ HDU 3635 带权并查集★ HDU 3047 带权并查集★ HDU 3038 HDU 2818 带权并查集★ HDU 3234 异或并查集(难)★★★ HDU 2121

最小生成树计数

情到浓时终转凉″ 提交于 2020-02-28 04:53:57
Minimum Spanning Tree http://acm.hdu.edu.cn/showproblem.php?pid=4408 模板题 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<stack> 5 #include<algorithm> 6 #define mt(a,b) memset(a,b,sizeof(a)) 7 using namespace std; 8 typedef __int64 LL; 9 class MinST_count { ///最小生成树计数o(~=MV^3)+o(MElogME) 10 typedef int typec;///边权的类型 11 typedef LL typer;///返回值类型 12 static const int ME=1024;///边的个数 13 static const int MV=128;///点的个数 14 struct E { 15 int u,v; 16 typec w; 17 friend bool operator <(E a,E b) { 18 return a.w<b.w; 19 } 20 } e[ME]; 21 typer mod,ans,mat[MV][MV]; 22 int n,le,fa[MV],ka

SDUT 周赛 2494 Minimum Spanning Tree? 最小生成树变形

最后都变了- 提交于 2020-02-28 04:52:09
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2494 题意: 给你一个图,该图可能存在很多最小生成树。求最小生成树可能包含的边的个数。 思路: 这里我们将权值相同的边看成一个块,按块来处理。按krusal的算法处理,检查每一块当该边加入后最小生成树后不会形成环就+1,这里我们先不把他们加入,检查完后再将边加入,这样就能保证可能加入最小生成树的相同的权值的边都加入了,并且我们也计数了。 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b)

最小生成树之prim算法

浪子不回头ぞ 提交于 2020-02-27 02:49:58
1.最小生成树三性质: 1.最小生成树边数等于顶点数减一,且树内不会有环; 2.对给定的G(V,E),其最小生成树可以不唯一,但其边权之和是唯一的; 3.最小生成树是无向图上生成的,因此其根节点可以是这棵树上的任意节点。 2.prim算法思想: 1.选择初始点把图中顶点分成两个不同的顶点集S(生成树的顶点集)V-S; 2.横跨两个不同顶点集的边中选择一条权值最小的边加入生成树中; 3.将该边另一点加入到顶点集S中,并从V-S中删除; 4.重复步骤2,3,直到V-S为空集。 3.算法图解如下: 4.模板代码如下: # include <stdio.h> # include <string.h> # define INF 0x7f7f7f7f //m二维数组储存图表,dis记录每两点间最小权值,vis标记是否被访问 int n , m [ 501 ] [ 501 ] , dis [ 501 ] , vis [ 501 ] ; int prim ( ) { int i , j , pos , min , result = 0 ; memset ( vis , 0 , sizeof ( vis ) ) ; vis [ 1 ] = 1 ; pos = 1 ; //从某点开始分别标记和记录该点 for ( i = 1 ; i <= n ; i ++ ) //low数组赋值 if ( i !=