最小生成树

最小生成树

假如想象 提交于 2020-02-08 23:10:35
prim算法 有两个集合,第一个集合,存放最小生成树,第二个集合,用来存放还没有进入最小生成树的结点。但这两个集合实际上是用同一个数组表示的。 我们用closedge[100]来表示这个数组,每个单元由“string Data;”和“int lowcost;”两部分组成。其中closedge[1]表示图中的第一个结点v1,closedge【1】.Data表示v1到最小生成树最短路径的结点(假设为v2),closedge【1】.lowcost就是v1到v2的距离。如果closedge【1】.lowcoat为0,就说明它已经在最小生成树中了。 prim算法的核心思想,就是以最小生成树为研究对象,每次在还没有进入最小生成树的结点中,找到路径最小的那个。假设目前的最小生成树为v2,v1是所有结点中,到它最短的一个,那么我们就把v1加入到最小生成树中,过程为:closedge【1】.lowcoat赋为0;把closedge【1】.Data赋为v1;在剩下的结点中,寻找是否有结点到v1的距离,小于此几点到v2的距离,如果有,那么此时此节点到最小生成树的距离,就是到v1的距离。总共n个结点,就重复此步骤n-1次。 # include <iostream> # include <string.h> using namespace std ; typedef struct Graph {

(最小生成树)洛谷P2916 [USACO08NOV]安慰奶牛Cheering up the Cow

社会主义新天地 提交于 2020-02-08 19:06:25
一、算法分析 刚看到题的时候没什么头绪,然后先模拟了一下题上的例子,感觉本题基本框架还是最小生成树,但是需要预处理一下,刚开始的想法是把点权加到边权上面,好能求最小生成树。然后开始的实现方式就是把每个边的边权加上这个边的起点的点权,样例也能过。但是交上去之后只能过第一个点。说明这样的方法不对,那么就需要建模求解正确方法,建模时将点分为三类,起点(根)、叶子、中间点。可以证明在一个生成树中,根据题目中的走法,叶子的度数为1,且经过一次,中间点的度数等于其经过次数,叶子和中间点这两类点可以合并,但是起点会多经过(谈话)一次,然后每条边会经过两次。如果先不算起点多的那次的话,新的边权就可以设置成原来边权乘2再加上边的起点和终点权值,然后跑一遍最小生成树,把最小生成树上所有边权加起来即可。然后再算多起点多出来的那一次,因为起点是可以自定的,所以要想谈话时间最小,那就可以把点权最小的点作为起点。所以最终答案就是最小生成树中,预处理后的新边权和再加上最小点权。 二、代码及注释 # include <iostream> # include <cstring> # include <cstdio> # include <algorithm> # define ll long long using namespace std ; const int maxn = 10050 ; int pa [

搜索与图论——最小生成树和二分图(2)

帅比萌擦擦* 提交于 2020-02-08 18:45:27
接上篇 对最小生成树的相关算法进行的讲解 此篇讲的是二分图的有关算法 二分图 二分图有一个很重要的性质: 无向图G=<V,E>是二部图当且仅当G中无奇数长度的回路(环) 可以推出:无向图G=<V,E>是二部图当且仅当能被二染色没有矛盾地染一遍 二分图的判定 思路:运用染色性质 主函数中: for ( int i = 1 ; i <= n ; i ++ ) { if ( ! color [ i ] ) //若未被染色 { if ( ! dfs ( i , 1 ) ) //dfs返回false即是遇到了染色矛盾 { flag = false ; //false即无法形成二分图 break ; } } } dfs函数: bool dfs ( int u , int c ) { color [ u ] = c ; for ( int i = h [ u ] ; i != - 1 ; i = ne [ i ] ) //遍历所有邻点 { int j = e [ i ] ; if ( ! color [ j ] ) { if ( ! dfs ( j , 3 - c ) ) return false ; //c==1-->3-c==2,c==2-->3-c==1即对不同的相邻点赋不同值。若返回矛盾则返回矛盾 } else if ( color [ j ] == c ) return false ;

最小生成树的拓展

爱⌒轻易说出口 提交于 2020-02-07 06:46:44
最小生成树的拓展 本文会随着弟弟我的学习进度来进行更新 度限制最小生成树 最小度生成树:np-hard 最小k度限制生成树:经典问题 做法(以下皆假设固定的点为rt): 删除rt点,并用剩下的点建一个最小生成树森林 如果有p个联通块,要满足最小k度限制生成树必须有 p < = k p<=k p < = k 。对于每个联通块,找出与rt相连的最小的一条边。这样就用了一个度数为p的解法 考虑如何从p转移到p+1。 假设 fa[v]为v的父亲, mx[v]为从rt到v路径上不与rt直接相连的边的最大值, w[u][v]为v与u的边的权值 则 m x [ v ] = m a x ( m x [ f a [ v ] ] , w [ v ] [ f a [ v ] ] ) mx[v]=max(mx[fa[v]],w[v][fa[v]]) m x [ v ] = m a x ( m x [ f a [ v ] ] , w [ v ] [ f a [ v ] ] ) 那么p+1的解法就有 a n s [ p + 1 ] = a n s [ p ] + m i n { − m x [ v ] + w [ v ] [ r t ] } ans[p+1]=ans[p]+min\{-mx[v]+w[v][rt]\} a n s [ p + 1 ] = a n s [ p ] + m i n { − m x

Truck History(建图+最小生成树)

大憨熊 提交于 2020-02-07 04:53:46
** Truck History(建图+最小生成树)** 先摆题 题目巨难读,可能是我英语太菜了吧。。 大意是这样的,给你n个七位字符串,两个字符串的距离就是不同的字母个数,字符串可以变形,每次改变一个字符,问如何能够用最少的操作让一个字符串挨个变成其他字符串的样子。答案输出1/操作次数。 多个输入,0截止。 题目一看,整活最小生成树,那么问题来了,怎么生成? 最小生成树有两种做法,一种是加边法()Kruskal算法),一种是加点法(Prim算法)。 https://blog.csdn.net/a2392008643/article/details/81781766 我是看这篇博客学的,这个东西不难,看懂思路自己就能写了,Kruskal算法需要并查集的基础。 在我学了最小生成树后做的第一道题是用加边法做的,然后,默默地看了一眼数据,加边法必tle,于是 这是一个错误的示范,大家不必细看。。 # include <iostream> # include <algorithm> # include <vector> # include <cstring> using namespace std ; struct node { int l , r , w ; bool operator < ( const node & a ) const { return w < a . w ; } }

第三种最小生成树算法 Borůvka算法

馋奶兔 提交于 2020-02-07 02:15:15
第三种最小生成树算法 Borůvka算法 基本思路: 用定点数组记录每个子树的最近邻居。 对于每一条边进行处理: 如果这条边连成的两个顶点同属于一个集合,则不处理,否则检测这条边连接的两个子树,如果是连接这两个子树的最小边,则更新 (合并)。 作用: 那么中算法有什么用呢,Kruskal,prim算法不好吗?它们好是好,但在某些题目里面可能用第三种算法更加优。对于那些点数n是1e5级别,边数m却是 n 2 n^2 n 2 级别的图,但每个点的最小边能很快算出来的题,求最小生成树我们不可能存得下边。这时候Borůvka算法用处就体现了,因为它的空间复杂度只跟点数有关。 代码: struct node { int x , y , w ; } edge [ M ] ; int d [ N ] ; // 各子树的最小连外边的权值 int e [ N ] ; // 各子树的最小连外边的索引 bool v [ M ] ; // 防止边重复统计 int fa [ N ] ; int find ( int x ) { return x == fa [ x ] ? x : ( fa [ x ] = find ( fa [ x ] ) ) ; } void join ( int x , int y ) { fa [ find ( x ) ] = find ( y ) ; } int Boruvka (

HOJ 1301 Jungle Roads (最小生成树)

霸气de小男生 提交于 2020-02-06 00:05:52
本题只是输入看起来比较复杂,细心一点处理好就可以了。 用三个一维数组代替二维数组存储边,降低时间复杂度。 # include <iostream> # include <cstring> using namespace std ; const int N = 30 , NN = 80 , INF = 99999999 ; int c1 [ NN ] , c2 [ NN ] , c3 [ NN ] , f [ N ] ; //三个一维数组代替二位数组存储数据,降低时间复杂度 int find ( int x ) { //寻找根节点 if ( x == f [ x ] ) return x ; f [ x ] = find ( f [ x ] ) ; return f [ x ] ; } int mer ( int x , int y ) { //将x和y所在的两个集合合并 x = find ( x ) ; y = find ( y ) ; if ( x != y ) f [ x ] = y ; return 1 ; } int main ( ) { int n , x , y , k , num , sum ; char xx , yy ; while ( cin >> n && n ) { num = 0 ; sum = 0 ; memset ( c1 , 0 , sizeof (

最小生成树

陌路散爱 提交于 2020-02-05 23:01:35
原文链接:https://blog.csdn.net/u011815404/article/details/84070642 原文链接:https://blog.csdn.net/u011815404/article/details/88625323 原文链接:https://blog.csdn.net/u011815404/article/details/88625346 目录 【概述】 【Prim算法】 【基本思想】 【算法分析】 【算法描述】 【模板】 【Kruskal算法】 【基本思想】 【算法分析】 【算法描述】 【概述】 对一个具有 n n n 个点的连通图进行遍历,对于遍历后的子图,其包含原图中所有的点且保持图连通,最后的结构一定是一个具有 n − 1 n-1 n − 1 条边的树,通常称为生成树。 在生成树问题中,最常见的问题就是最小生成树问题,所谓最小生成树,就是对于一个有 n n n 个点的无向连通图的生成树,其包含原图中的所有点,且保持图连通的边权总和最少的边。 简单来说,对于一个有 n n n 个点的图,边一定是大于等于 n − 1 n-1 n − 1 条的,最小生成树,就是在这些边中选择 n − 1 n-1 n − 1 条出来连接所有的 n n n 个点,且这 n − 1 n-1 n − 1 条边的边权之和是所有方案中最小的。 最小生成树具有以下两条性质:

图论

南笙酒味 提交于 2020-02-05 19:02:37
文章目录 1.最小生成树 1.1普利姆(Prim)算法 1.2卡鲁斯卡尔(Kruskal)算法 2.最短路径 2.1迪杰斯特拉(Dijikstra)算法 2.2弗洛伊德(Floyd)算法 3.拓扑排序 4.关键路径 1.最小生成树 在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边,而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得 w(T) 最小,则此 T 为 G 的最小生成树。 最小生成树其实是最小权重生成树的简称。 生成树和最小生成树有许多重要的应用。 例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。 使用例 用最小的权值连接所有顶点 图的实现类 JAVA实现数据结构:图 1.1普利姆(Prim)算法 Prim算法简述 1).初始化:Vnew= {x},其中x为集合V中的任一节点(起始点),Enew= {},为空; 2).重复下列操作,直到Vnew= V: a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条具有相同权值的边,则可任意选取其中之一); b