贪心策略-最小生成树prim和克利斯卡尔JAVA算法源程序

合集下载

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

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

Kruskal克鲁斯卡尔最⼩⽣成树算法(贪⼼算法)1. /*2. * Introduction to Algorithms3. * Chapter 23 --- MST.Kruskal4. * Tanky Woo @ 5. * 2012.1.76. */7.8. #include <</span>iostream>9. #include <</span>algorithm>10. using namespace std;11.12. const int maxint = 999999;13.14. typedef struct Road{15. int c1, c2;// a到b16. int value;//权值17. }Road;18.19. int no;20. int line;//记录实际关系数21. Road road[100];//设⼀个⽐较⼤的值,实际看输⼊最⼩⽣成树中:边数e=n-122. int node[101];//最⼩⽣成树:n顶点数23.24. bool myCmp(const Road &a,const Road &b)25. {26. if(a.value <</span> b.value)27. return 1;28. return 0;29. }30.31. //node[2]=1 node[8]=1 ,node[3]=1,共同的祖先,如果(3,8)加进去,则构成回路,不要32. //有点像并查集33. int Find_Set(int n)34. {35. if(node[n]==-1)36. return n;37. return node[n]= Find_Set(node[n]);38. }39.40. bool Merge(int s1,int s2)41. {42. int r1 = Find_Set(s1);43. int r2 = Find_Set(s2);44. if(r1 == r2)//如果相等证明构成回路,则直接返回⼀个0,不要把顶点加进来(下⼀步是加进去的)45. return 0;46. if(r1 <</span> r2)47. node[r2]= r1;48. else49. node[r1]= r2;50. return 1;51. }52.53. int main()54. {55. freopen("input.txt","r", stdin);56. //初始化全为-157. memset(node,-1, sizeof(node));58. scanf("%d",&no);59. scanf("%d",&line);60. int i;61. for(i=0; i<</span>line; ++i)62. {63. cin >> road[i].c1 >> road[i].c2 >> road[i].value;64. }65. sort(road, road+line, myCmp);66. int sum = 0, count = 0;// sum是MST的值,count是记录已使⽤的点数67. for(i=0; i<</span>line; ++i)68. {69. if(Merge(road[i].c1, road[i].c2))//如果返回的为0,则证明构成回路,不要加进70. {71. count ++;72. sum += road[i].value;73. }74. if(count == no-1)//e=n-1已经连通,可以退出75. break;76. }77. cout <</span><</span> sum <</span><</span> endl;78. return 0;79. }80.81.82. /*83. input.txt:84. 985. 1486. 1 2 487. 1 8 888. 2 3 889. 2 8 1190. 3 4 791. 3 6 492. 3 9 293. 4 5 994. 4 6 1495. 5 6 1096. 6 7 297. 7 8 198. 7 9 699. 8 9 7100. */。

最小生成树问题---Prim算法与Kruskal算法实现(MATLAB语言实现)

最小生成树问题---Prim算法与Kruskal算法实现(MATLAB语言实现)

最⼩⽣成树问题---Prim算法与Kruskal算法实现(MATLAB语⾔实现) 2015-12-17晚,复习,甚是⽆聊,阅《复杂⽹络算法与应⽤》⼀书,得知最⼩⽣成树问题(Minimum spanning tree)问题。

记之。

何为树:连通且不含圈的图称为树。

图T=(V,E),|V|=n,|E|=m,下列关于树的说法等价:T是⼀个树。

T⽆圈,且m=n-1。

T连通,且m=n-1。

T⽆圈,但每加⼀新边记得到唯⼀⼀个圈。

T连通,但任舍去⼀边就不连通。

T中任意两点,有唯⼀道路相连。

何为⽣成树:若图G=(V,E)的⽣成⼦图是⼀棵树,则称该树为图G的⽣成树,也称⽀撑树,简称为图G的数。

图G中属于⽣成树的边称为数枝(Branch)。

何为最⼩⽣成树:连通图G=(V,E),每条边上有⾮负权L(e)。

⼀棵树上所有树枝权的总和,称为这个⽣成树的权。

具有最⼩权的⽣成树称为最⼩⽣成树,也就是说最⼩⽀撑树,简称最⼩树。

私以为,两种算法其实都是贪⼼,所以需要严格的证明。

由于最近时间零散、数学久置未学、对算法领域没有系统了解。

所以不进⾏深⼊探讨(也就是说证明),仅以⼀个简单实例做⼀个⼊门级的了解。

Prim算法: 给定连通赋权图G=(V,E,W),其中W为邻接矩阵,设两个集合P和Q,其中P⽤于存放G的最⼩⽣成树中的节点,集合Q存放G的最⼩G的最⼩⽣成树中的边。

另集合P的初值为P={v1}(假设构造最⼩⽣成树时从v1出发),集合Q的初值为P={空集}。

(1)P = {v1},Q = {空集}; (2)while P ~= Q 找到最⼩边pv,其中p∈P,v∈V-P; P = P + {v}; Q = Q + {pv}; end Kruskal算法 (1)选e1∈E(G),使得w(e1) = min(选e1的权值最⼩)。

(2)e1,e2,...,e i已选好,则从E(G)-{e1,e2,...,e i}中选取e i+1,使得G[{e1,e2,...,e i,e i+1}]中⽆圈,且,w(e i+1) = min。

实验 1 贪心算法实现最小生成树

实验 1 贪心算法实现最小生成树

实验一用贪心算法实现最小生成树问题一.实验目的1.熟悉贪心算法的基本原理和使用范围。

二.实验内容及要求内容:任选一种贪心算法(prim或Kruskal),求解最小生成树。

对算法进行编程。

要求:使用贪心算法编程,求解最小生成树问题三.程序列表(1)prim算法#include<stdio.h>#define INF 32766#define max 40void prim(int g[][max],int n){int lowcost[max],closest[max];int i,j,k,min;for(i=2;i<=n;i++){lowcost[i]=g[1][i];closest[i]=1;}lowcost[1]=0;for(i=2;i<=n;i++){min=INF;k=0;for(j=2;j<=n;j++){if((lowcost[j]<min)&&(lowcost[j]!=0)){min=lowcost[j];k=j;}}printf("(%d,%d)%d\t",closest[k],k,min);lowcost[k]=0;for(j=2;j<=n;j++){if(g[k][j]<lowcost[j]){lowcost[j]=g[k][j];closest[j]=k;}}printf("\n");}}int adj(int g[][max]){int n,i,j,v1,v2,weight,m;printf("输入顶点数 n=:");scanf("%d",&n);for(i=1;i<=n;i++)for(j=1;j<=n;j++)g[i][j]=INF;while(v1!=0&&v2!=0&&weight!=0)//只要输入0 0 0就结束{printf("v1,v2,weight=");scanf("%d %d %d",&v1,&v2,&weight);g[v1][v2]=weight;g[v2][v1]=weight;}return(n);}void prg(int g[][max],int n){int i,j;for(i=0;i<=n;i++)printf("%d\t",i);for(i=1;i<=n;i++){printf("\n%d\t",i);for(j=1;j<=n;j++)printf((g[i][j]==INF)?"\t":"%d\t",g[i][j]);}printf("\n");}void main(){int g[max][max],n,i;n=adj(g);printf("输出无向图的邻接矩阵:\n");prg(g,n);printf("输出最小生成树:\n");prim(g,n);}四.实验结果。

最小生成树的Prim算法以及Kruskal算法的证明

最小生成树的Prim算法以及Kruskal算法的证明

最⼩⽣成树的Prim算法以及Kruskal算法的证明Prime算法的思路:从任何⼀个顶点开始,将这个顶点作为最⼩⽣成树的⼦树,通过逐步为该⼦树添加边直到所有的顶点都在树中为⽌。

其中添加边的策略是每次选择外界到该⼦树的最短的边添加到树中(前提是⽆回路)。

Prime算法的正确性证明:引理1:对于连通图中的顶点vi,与它相连的所有边中的最短边⼀定是属于最⼩⽣成树的。

引理2:证明:假设最⼩⽣成树已经建成;(vi, vj)是连接到顶点vi的最短边,在最⼩⽣成树中取出vi,断开连接到vi的边,则⽣成树被拆分成1、顶点vi2、顶点vj所在的连通分量(单独⼀个顶点也看作⼀个独⽴的连通分量)3、其余若⼲个连通分量(个数⼤于等于0)三个部分现在要重建⽣成树,就要重新连接之前被断开的各边虽然不知道之前被断开的都是哪⼏条边,但是可以通过这样⼀个简单的策略来重建连接:将vi分别以最⼩的成本逐个连接到这若⼲个互相分离的连通分量;具体来说,就是要分别遍历顶点vi到某个连通分量中的所有顶点的连接,然后选择其中最短的边来连接vi和该连通分量;⽽要将vi连接到vj所在的连通分量,显然通过边(vi, vj)连接的成本最低,所以边(vi, vj)必然属于最⼩⽣成树(如果连接到vi的最短边不⽌⼀条,只要任意挑选其中的⼀条(vi, vj)即可,以上的证明对于这种情况同样适⽤)。

这样我们就为原来只有⼀个顶点vi的⼦树添加了⼀个新的顶点vj及新边(vi, vj);接下来只要将这棵新⼦树作为⼀个连通⼦图,并且⽤这个连通⼦图替换顶点vi重复以上的分析,迭代地为⼦树逐个地添加新顶点和新边即可。

Kruskal算法:通过从⼩到⼤遍历边集,每次尝试为最⼩⽣成树加⼊当前最短的边,加⼊成功的条件是该边不会在当前已构建的图中造成回路,当加⼊的边的数⽬达到n-1,遍历结束。

Kruskal算法的正确性证明:Kruskal算法每次为当前的图添加⼀条不会造成回路的新边,其本质是逐步地连接当前彼此分散的各个连通分量(单个顶点也算作⼀个连通分量),⽽连接的策略是每次只⽤最⼩的成本连接任意两个连通分量。

最小生成树之Prim算法

最小生成树之Prim算法

最小生成树之Prim算法1、生成树的概念连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G 的生成树。

生成树是连通图的极小连通子图。

所谓极小是指:若在树中任意增加一条边,则将出现一个回路;若去掉一条边,将会使之变成非连通图。

生成树各边的权值总和称为生成树的权。

权最小的生成树称为最小生成树。

2、最小生成树的性质用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的。

按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。

3、构造最小生成树,要解决以下两个问题:( 1).尽可能选取权值小的边,但不能构成回路(也就是环)。

(2).选取n-1条恰当的边以连接网的 n个顶点。

求最小生成树的算法一般都使用贪心策略,有Prim算法和Krusal算法等。

普里姆算法的基本思想:1)清空生成树,任取一个顶点加入生成树;2)在那些一个端点在生成树里,另一个端点不在生成树里的边中,选取一条权最小的边,将它和另一个端点加进生成树;3)重复步骤2,直到所有的顶点都进入了生成树为止,此时的生成树就是最小生成树。

即: 从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点v加入到生成树的顶点集合U中。

以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把它的顶点 v加入到集合U中。

如此继续下去,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

编写程序:对于如下一个带权无向图,给出节点个数以及所有边权值,用Prim算法求最小生成树。

代码的注释我写得很详细,方便理解,有几点需要说明一下。

(1)、2个for循环都是从2开始的,因为一般我们默认开始就把第一个节点加入生成树,因此之后不需要再次寻找它。

( 2)、lowcost[i]记录的是以节点i为终点的最小边权值。

初始化时因为默认把第一个节点加入生成树,因此lowcost[i] = graph[1][i],即最小边权值就是各节点到1号节点的边权值中最小的。

克鲁斯卡尔算法求最小生成树完整代码

克鲁斯卡尔算法求最小生成树完整代码

克鲁斯卡尔算法是一种用来求解最小生成树(Minimum Spanning Tree)的经典算法,它采用了贪心策略,能够高效地找到图中的最小生成树。

下面将为大家介绍克鲁斯卡尔算法的完整代码,希望对大家有所帮助。

1. 算法思路克鲁斯卡尔算法的基本思路是:首先将图中的所有边按照权值进行排序,然后从小到大依次考虑每条边,如果加入该边不会构成环,则将其加入最小生成树中。

在算法执行过程中,我们需要使用并查集来判断是否会构成环。

2. 代码实现接下来,我们将给出克鲁斯卡尔算法的完整代码,代码使用C++语言编写,具体如下:```cpp#include <iostream>#include <vector>#include <algorithm>using namespace std;// 定义图的边struct Edge {int u, v, weight;Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {} };// 定义并查集class UnionFind {private:vector<int> parent;public:UnionFind(int n) {parent.resize(n);for (int i = 0; i < n; i++) {parent[i] = i;}}int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}void Union(int x, int y) {int root_x = find(x);int root_y = find(y);if (root_x != root_y) {parent[root_x] = root_y;}}};// 定义比较函数用于排序bool cmp(const Edge a, const Edge b) {return a.weight < b.weight;}// 克鲁斯卡尔算法vector<Edge> kruskal(vector<Edge> edges, int n) { // 先对边进行排序sort(edges.begin(), edges.end(), cmp);// 初始化最小生成树的边集vector<Edge> res;UnionFind uf(n);for (int i = 0; i < edges.size(); i++) {int u = edges[i].u, v = edges[i].v, weight = edges[i].weight; // 判断是否构成环if (uf.find(u) != uf.find(v)) {uf.Union(u, v);res.push_back(edges[i]);}}return res;}// 测试函数int m本人n() {vector<Edge> edges;edges.push_back(Edge(0, 1, 4));edges.push_back(Edge(0, 7, 8));edges.push_back(Edge(1, 2, 8));edges.push_back(Edge(1, 7, 11));edges.push_back(Edge(2, 3, 7));edges.push_back(Edge(2, 5, 4));edges.push_back(Edge(2, 8, 2));edges.push_back(Edge(3, 4, 9));edges.push_back(Edge(3, 5, 14));edges.push_back(Edge(4, 5, 10));edges.push_back(Edge(5, 6, 2));edges.push_back(Edge(6, 7, 1));edges.push_back(Edge(6, 8, 6));edges.push_back(Edge(7, 8, 7));vector<Edge> res = kruskal(edges, 9);for (int i = 0; i < res.size(); i++) {cout << res[i].u << " " << res[i].v << " " << res[i].weight << endl;}return 0;}```3. 算法实例上述代码实现了克鲁斯卡尔算法,并对给定的图进行了最小生成树的求解。

贪心法求最小生成树算法

贪心策略求最小生成树问题设G =(V ,E )是一个无向连通网,生成树上各边的权值之和称为该生成树的代价,在G 的所有生成树中,代价最小的生成树称为最小生成树(Minimal Spanning Trees )。

最小生成树问题至少有两种合理的贪心策略:(1)最近顶点策略:任选一个顶点,并以此建立起生成树,每一步的贪心选择是简单地把不在生成树中的最近顶点添加到生成树中。

Prim 算法就应用了这个贪心策略,它使生成树以一种自然的方式生长,即从任意顶点开始,每一步为这棵树添加一个分枝,直到生成树中包含全部顶点。

设图G 中顶点的编号为0~n-1,Prim 算法如下: 算法7.4——Prim 算法1. 初始化两个辅助数组lowcost 和adjvex ;2. U={u0}; 输出顶点u0; //将顶点u0加入生成树中3. 重复执行下列操作n-1次3.1 在lowcost 中选取最短边,取adjvex 中对应的顶点序号k ; 3.2 输出顶点k 和对应的权值; 3.3 U=U+{k};3.4 调整数组lowcost 和adjvex ; 上述伪代码中,数组closest[j]是j(jÎV-S)在S 中的领接顶点,它与j 在S 中的其它顶点相比较有c[j][cloest[j]]<=c[j][k]。

lowest[j]的值就是c[j][cloest[j]]。

在算法执行过程中,先找出V-S 中是lowest 值最小的顶点j ,然后根据数组closest 选取边(j,cloest[j]),最后将j 添加到S(d) U ={A , F , C , D } (e) U ={A , F , C , D , E } (f) U ={A , F , C , D , E , B }cost={(A , B )34, (F , E )26} cost={(E , B )12}B 25 12 34 19264638 1725 25 12 34 19264638 1725 25 12 34 19264638 1725 A A A B B EEEF F F DDD34 34 34 17171725 12 1926463825 25 12 1926463825 25 12 1926463825 (a) 连通网,U ={A } (b) U ={A , F } (c) U ={A , F ,C }cost={(A , B )34,(A , C )46, cost={(A , B )34,(F , C )25, cost={(A , B )34, (C , D )17,(F , E )26}BBBA A A EEEF F F DDDCCCCCC中,并对closest和lowest作必要的修改。

最小生成树算法总结

最小生成树算法总结最小生成树是指在一个无向连通图中,找到一个子树,使得这棵子树中所有边的权值之和最小。

最小生成树可以用于最优化问题,例如道路铺设、网络布线等。

下面将介绍三种最小生成树算法:Prim算法、Kruskal算法、Boruvka算法。

1. Prim算法Prim算法是一种贪心算法,从一个点开始,每次添加连接到已有集合中的最小边,直到所有点都在同一个集合中。

可以用以下步骤描述Prim算法:(1) 选择一个起点,将该起点加入最小生成树的顶点集合,然后将该顶点相邻的边加入边集合中。

(2) 从边集合中找到权值最小的一条边,将该边对应的顶点加入最小生成树的顶点集合,同时将该顶点相邻的边加入边集合中。

(3) 重复上述步骤,直到所有顶点都在最小生成树的顶点集合中。

Prim算法的实现可以使用堆优化,时间复杂度为O(E + VlogV),其中E为边数,V为顶点数。

2. Kruskal算法Kruskal算法也是一种贪心算法,与Prim算法不同的是,Kruskal算法是按照边的权值从小到大依次添加,直到所有顶点都在同一个集合中。

可以用以下步骤描述Kruskal算法:(1) 将所有边按照权值从小到大排序。

(2) 依次取出排好序的边,如果该边所连接的两个顶点不在同一个集合中,就将这条边加入最小生成树的边集合中,并将这两个顶点合并到同一个集合中。

(3) 重复步骤(2),直到所有顶点都在同一个集合中。

Kruskal算法的实现可以使用并查集,时间复杂度为O(ElogE),其中E为边数。

3. Boruvka算法Boruvka算法是一种基于集合的分治算法,与Prim算法和Kruskal算法不同,Boruvka算法的时间复杂度是线性的。

可以用以下步骤描述Boruvka算法:(1) 对每个顶点建立单元素集合。

(2) 对每个集合,选择与该集合相连的最小权值的边,将这些边添加到最小生成树的边集合中,并将这些集合合并到同一个集合中。

(3) 如果只剩下一个集合,算法结束。

数学建模-最小生成树-kruskal算法及各种代码

kruskal算法及代码之阳早格格创做---含真代码、c代码、matlab、pascal等代码K r u s k a l算法屡屡采用n- 1条边,所使用的贪婪规则是:从剩下的边中采用一条不会爆收环路的具备最小泯灭的边加进已采用的边的集中中.注意到所采用的边若爆收环路则不可能产死一棵死成树.K r u s k a l算法分e 步,其中e 是搜集中边的数目.按泯灭递加的程序去思量那e 条边,屡屡思量一条边.当思量某条边时,若将其加进到已选边的集中中会出现环路,则将其扬弃,可则,将它选进.目录Kruskal算法1.算法定义举例形貌Kruskal算法的代码真止1.真代码C代码真止matlab代码真止pascal代码真止Kruskal算法1.算法定义举例形貌Kruskal算法的代码真止1.真代码C代码真止matlab代码真止pascal代码真止算法定义克鲁斯卡我算法假设WN=(V,{E}) 是一个含有n 个顶面的连通网,则依照克鲁斯卡我算法构制最小死成树的历程为:先构制一个只含n 个顶面,而边集为空的子图,若将该子图中各个顶面瞅成是各棵树上的根结面,则它是一个含有n 棵树的一个森林.之后,从网的边集E 中采用一条权值最小的边,若该条边的二个顶面分属分歧的树,则将其加进子图,也便是道,将那二个顶面分别地方的二棵树合成一棵树;反之,若该条边的二个顶面已降正在共一棵树上,则不可与,而该当与下一条权值最小的边再试之.依次类推,曲至森林中惟有一棵树,也即子图中含有n-1条边为止.举例形貌克鲁斯卡我算法(Kruskal's algorithm)是二个典范的最小死成树算法的较为简朴明白的一个.那内里充分体现了贪心算法的粗髓.大概的过程不妨用一个图去表示.那里的图的采用借用了Wikipedia上的那个.非常浑晰且曲瞅.最先第一步,咱们有一弛图,有若搞面战边如下图所示:第一步咱们要搞的事务便是将所有的边的少度排序,用排序的截止动做咱们采用边的依据.那里再次体现了贪心算法的思维.资材排序,对付局部最劣的资材举止采用.排序完毕后,咱们率先采用了边AD.那样咱们的图便形成了第二步,正在剩下的变中觅找.咱们找到了CE.那里边的权沉也是5依次类推咱们找到了6,7,7.完毕之后,图形成了那个格式..下一步便是闭键了.底下采用那条边呢?BC大概者EF 吗?皆不是,纵然目前少度为8的边是最小的已采用的边.然而是目前他们已经连通了(对付于BC不妨通过CE,EB去对接,类似的EF不妨通过EB,BA,AD,DF去接连).所以咱们不需要采用他们.类似的BD也已经连通了(那里上图的连通线用白色表示了).末尾便剩下EG战FG了.天然咱们采用了EG.末尾乐成的图便是下图:.到那里所有的边面皆已经连通了,一个最小死成树构修完毕.编写本段Kruskal算法的代码真止真代码MST-KRUSKAL(G,w)C代码真止Copyright (c) 2002,2006 by ctu_85All Rights Reserved.*//* I am sorry to say that the situation of unconnected graph is not concerned */#include "stdio.h"#define maxver 10#define maxright 100int G[maxver][maxver],record=0,touched[maxver][maxver]; int circle=0;intFindCircle(int,int,int,int);int main(){int path[maxver][2],used[maxver][maxver];inti,j,k,t,min=maxright,exsit=0;int v1,v2,num,temp,status=0;restart:printf("Please enter the number of vertex(s) in the graph:\n"); scanf("%d",&num);if(num>maxver||num<0){printf("Error!Pleasereinput!\n");goto restart;}for(j=0;j<num;j++)for(k=0;k<num;k++){if(j==k)G[j][k]=maxright;used[j][k]=1;touched[j][k]=0;}elseif(j<k){re:printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\n",j+1,k+1);scanf("%d",&temp);if(temp>=maxright||temp<-1){printf("Invalid input!\n");goto re;}if(temp==-1)temp=maxright;G[j][k]=G[k][j]=temp;used[j][k]=used[k][j]=0;touched[j][k]=touched[k][j]=0;}for(j=0;j<num;j++){path[j][0]=0;path[j][1]=0;}for(j=0;j<num;j++){status=0;for(k=0;k<num;k++)if(G[j][k]<maxright){status=1;break;}if(status==0)break;}for(i=0;i<num-1&&status;i++) {for(j=0;j<num;j++)for(k=0;k<num;k++)if(G[j][k]<min&&!used[j][k]){v1=j;v2=k;min=G[j][k];}if(!used[v1][v2]){used[v1][v2]=1;used[v2][v1]=1;touched[v1][v2]=1;touched[v2][v1]=1;path[0]=v1;path[1]=v2;for(t=0;t<record;t++)FindCircle(path[t][0],path[t][0],num,path[t][0]); if(circle){/*if a circle exsits,roll back*/circle=0;i--;exsit=0;touched[v1][v2]=0;touched[v2][v1]=0;min=maxright;}else{record++;min=maxright;}}}if(!status)printf("We cannot deal with it because the graph is not connected!\n");else{for(i=0;i<num-1;i++)printf("Path %d:vertex %d tovertex %d\n",i+1,path[0]+1,path[1]+1);}return 1;}intFindCircle(intstart,intbegin,inttimes,int pre) { /* to judge whether a circle is produced*/ inti;for(i=0;i<times;i++)if(touched[begin]==1){if(i==start&&pre!=start){circle=1;return 1;break;}elseif(pre!=i)FindCircle(start,i,times,begin);elsecontinue;}return 1;}matlab代码真止functionKruskal(w,MAX)%此步调为最小收撑树的Kruskal算法真止%w为无背图的距离矩阵,故为对付称矩阵%MAX为距离矩阵中∞的本质输进值%时间:2011年6月22日0:07:53len=length(w); %图的面数edge=zeros(len*(len-1),3); %用于死存图中的边count=1; %图中的边数for i=1:len-1 %循环距离矩阵,记录死存边for j=i+1:lenif w(i,j)~=MAXedge(count,1)=w(i,j);edge(count,2)=i;edge(count,3)=j;count=count+1;endendendedge=edge(1:count-1,:); %去掉无用边[tmp,index]=sort(edge(:,1)); %所有边按降序排序i=3; %本去尝试边数为3条(3条以下无法形成圈,即无需检测)while 1x=findcycle(edge(index(1:i),:),len); %检测那些边是可形成圈if xindex(i)=0; %若形成圈,则将该边对付应的index项标记表记标帜为0,以便与消elsei=i+1; %若不形成圈,则i加1,加进下一边检测endindex=index(index>0); %将形成圈的边从index中与消ifi==lenbreak; %找到切合条件的面数减一条的边,即找到一个最小收撑树endendindex=index(1:len-1); %截短index矩阵,死存前len-1项%%%%%%%%%%%% 截止隐现%%%%%%%%%%%%%s=sprintf('\n\t%s\t%s\t %s\t','边端面','距离','是可正在最小收撑树');fori=1:count-1edge_tmp=edge(i,:);if ~isempty(find(index==i,1))s_tmp=sprintf('\n \t (%d,%d)\t %d\t %s\t',edge_tmp(2),edge_tmp(3),edge_tmp(1),'√');elses_tmp=sprintf('\n \t (%d,%d)\t %d\t %s\t',edge_tmp(2),edge_tmp(3),edge_tmp(1),'×');ends=strcat(s,s_tmp);enddisp(s);endfunctionisfind=findcycle(w,N)%本步调用于推断所给的边是可形成圈:有圈,返回1;可则返回0%w:输进的边的矩阵%N:本图的面数%本理:不竭与消出现次数小于2的端面地方的边,末尾瞅察是可有边留住len=length(w(:,1));index=1:len;while 1num=length(index); %边数p=zeros(1,N); %用于死存各面的出现的次数(一条边对付应二个端面)for i=1:num %统计各面的出现次数p(w(index(i),2))=p(w(index(i),2))+1;p(w(index(i),3))=p(w(index(i),3))+1;endindex_tmp=zeros(1,num); %记录与消出现次数小于2的端面地方的边的边的下标集中discard=find(p<2); %找到出现次数小于2的端面count=0; %记录结余的边数fori=1:num%推断各边是可有仅出现一次端面——不,则记录其序号于index_tmpif ~(~isempty(find(discard==w(index(i),2),1)) ||~isempty(find(discard==w(index(i),3),1)))count=count+1;index_tmp(count)=index(i);endendif num==count %当不边被被与消时,循环停止index=index_tmp(1:count); %革新indexbreak;elseindex=index_tmp(1:count); %革新indexendendif isempty(index) %若末尾剩下的边数为0,则无圈isfind=0;elseisfind=1;endend%% a =[% 0 3 2 3 100 100100% 3 0 2 100 100100 6% 2 2 0 3 100 1 100% 3 100 3 0 5 100 100% 100 100100 5 0 4 6% 100 100 1 100 4 0 5% 100 6 100 6 100 5 0];%% Kruskal(a,100)pascal代码真止{最小死成树的Kruskal算法.Kruskal算法基础思维:屡屡选不属于共一连通分量(包管不死成圈)且边权值最小的顶面,将边加进MST,并将地方的2个连通分量合并,曲到只剩一个连通分量排序使用Quicksort(O(eloge))查看是可正在共一连通分量用Union-Find,屡屡Find战union运算近似常数Union-Find使用rank开收式合并战路径压缩总搀纯度O(eloge)=O(elogv) (果为e<n(n-1)/2)}constmaxn=100;maxe=maxn*maxn;typeedge=recorda,b :integer; //边的2个顶面len :integer; //边的少度end;varedges :array[0..maxe]of edge; //死存所有边的疑息p,r :array[0..maxn]of integer; //p死存i的女亲节面,r用去真止Union-Find的rank开收式n,e :integer; //n为顶面数,e为边数procedure swap(a,b:integer); //接换beginedges[0]:=edges[a];edges[a]:=edges[b];edges[b]:=edges[0];end;procedure quicksort(l,r:integer); //赶快排序varx,i,j :integer;beginx:=edges[random(r-l+1)+l].len;i:=l;j:=r;repeatwhile edges[i].len<x do inc(i);while edges[j].len>x do dec(j);ifi<=j thenbeginswap(i,j);inc(i);dec(j);enduntili>j;if l<j then quicksort(l,j);ifi<r then quicksort(i,r);end;procedureinit;vari :integer;beginassign(input,'g.in');reset(input);readln(n,e);for i:=1 to e do readln(edges[i].a,edges[i].b,edges[i].len); //从文献读进图的疑息for i:=1 to n do p[i]:=i; //初初化并查集randomize;quicksort(1,e); //使用赶快排序将边按权值从小到大排列end;function find(x:integer):integer; //并查集的Find,用去推断2个顶面是可属于一个连通分量beginif x<>p[x] then p[x]:=find(p[x]);find:=p[x]end;procedure union(a,b:integer); //如果不属于且权值最小则将2个顶面合并到一个连通分量vart :integer;begina:=find(a);b:=find(b);if r[a]>r[b] then begin t:=a;a:=b;b:=t end;if r[a]=r[b]then inc(r[a]);p[a]:=b;end;procedure kruskal; //主历程varen :integer; //en为目前边的编号count :integer; //统计举止了频频合并.n-1次合并后便得到最小死成树tot :integer; //统计最小死成树的边权总战begincount:=0;en:=0; tot:=0;while count<n-1 dobegininc(en);with edges[en] dobeginif find(a)<>find(b) thenbeginunion(a,b);writeln(a,'--',b,':',len);inc(tot,len);inc(count);end;end;end;writeln('Total Length=',tot)end;{===========main==========} begininit;kruskal;end.例题详睹vijos p1045 Kerry 的电缆搜集typerec=recordx,y:longint;cost:real;end;varf:array[1..1000000] of rec;s,ans:real;i,n,m,k,dad:longint;father:array[1..1000000] of longint; procedurekp(l,r:longint);vari,j:longint;xx:real;y:rec;begini:=l;j:=r;xx:=f[(i+j) div 2].cost;repeatwhile xx>f[i].cost do inc(i);while xx<f[j].cost do dec(j);ifi<=j thenbeginy:=f[i];f[i]:=f[j];f[j]:=y;inc(i);dec(j);end;untili>j;ifi<r then kp(i,r);if l<j then kp(l,j);end;function find(x:longint):longint; beginif father[x]=x then exit(x);father[x]:=find(father[x]);exit(father[x]);end;procedure union(x,y:longint;j:real); beginx:=find(x);y:=find(y);if x<>y thenbeginfather[y]:=x;ans:=ans+j;inc(k);end;end;beginreadln(s);readln(n);m:=0;while not eof do begininc(m);with f[m] doreadln(x,y,cost); end;if m<n-1 then beginwriteln('Impossible'); exit;end;fori:=1 to n do father[i]:=i;kp(1,m);k:=0;fori:=1 to m dobeginif k=n-1 then break;union(f[i].x,f[i].y,f[i].cost);end;if k<n-1 thenbeginwriteln('Impossible');exit;end;ifans>s then writeln('Impossible') elsewriteln('Need ',ans:0:2,' miles of cable');end.Kruskal算法适用于边稀稀的情形,而Prim算法适用于边稀稀的情形其余最小死成树算法c++代码真止#include <stdio.h>#include <stdlib.h>#include <vector>using namespace std;#define MAXNUM_VERTEX 20 //最多有20个顶面#define MAXNUM_EDGE 21typedefstruct{intv,w;int weight;}Edge;typedefstruct{int vertex[MAXNUM_VERTEX];Edge edge[MAXNUM_EDGE];intnum_vertex,num_edge;}Graph;Graph graph; //声明为齐部变量boolsearch_vertex(intver){for(inti=0; i<graph.num_vertex; i++)if(ver == graph.vertex[i] )return 1;printf("the vertex %d you input is not existed! \n",ver); return 0;}voidcreate_graph(){//输进顶面疑息printf("input the number of vertex in the graph\n");scanf(" %d",&graph.num_vertex);printf("input the vertex of graph,like 1,2\n");for(inti=0; i<graph.num_vertex; i++)scanf(" %d",&graph.vertex[i]);//输进边疑息printf("input the number of edge in the graph\n");scanf(" %d",&graph.num_edge);printf("intput the edge of graph and the weight of line,like 1-2 5\n");for(int j=0; j<graph.num_edge; j++){p1:inta,c,d;char b;scanf(" %d %c %d %d",&a,&b,&c,&d);if(search_vertex(a) && search_vertex(c) ){graph.edge[j].v=a;graph.edge[j].w=c;graph.edge[j].weight=d;}elsegoto p1;}}voidsort_by_weight(){for(inti=1; i<graph.num_edge; i++){Edge temp=graph.edge[i];for(int j=i-1; j>=0 && graph.edge[j].weight>temp.weight; j--) graph.edge[j+1]=graph.edge[j];graph.edge[j+1]=temp;}}/*不相接集处理函数*/inline void makeset(vector<int> & array){for(inti=0; i<array.size(); i++)array[i]=i;}intfindset(vector<int> & parent,inti){if(i != parent[i])i=parent[i];returni;}inline void merge(vector<int> & parent,inti,int j) {parent[i]=j;}/*不相接集处理函数*/voidkruskal(){intnum_ver=graph.num_vertex;int count=0;vector<int> parent_ver;parent_ver.resize(num_ver);/*核心部分是用不相接集中成树*/ makeset(parent_ver);printf("the edge of min tree as follow: \n");for( inti=0; i<num_ver && count<num_ver-1; i++ ) //count 表示合并(merge)的次数num_ver-1次{int m=graph.edge[i].v;int n=graph.edge[i].w;int w=graph.edge[i].weight;if(findset(parent_ver,m) != findset(parent_ver,n)) //当属于分歧的集中时,则将该边增加进树中{printf("(%d %d) %d\n",m,n,w);merge(parent_ver,m,n);count++;}}}voidprint_edge(){printf("the graph you input as follow: \n");for(inti=0; i<graph.num_edge; i++)printf("%d-%d the weightis: %d\n",graph.edge[i].v,graph.edge[i].w,graph.edge[i].weight);}void main(){create_graph();sort_by_weight();print_edge();kruskal();}java代码真止importjava.util.ArrayList;importjava.util.Collections;class Bian implements Comparable // 二面之间的加权边{private intfirst,second;// 表示一条边的二个节面private int value;// 权值publicBian(intfirst,intsecond,int value) {this.first = first;this.second = second;this.value = value;}publicintgetFirst() {return first;}publicintgetSecond() {return second;}publicintgetValue() {return value;}@OverridepublicintcompareTo(Object arg0) {return value > ((Bian) arg0).value 1: (value == ((Bian) arg0).value 0 : -1);}@Overridepublic String toString() {return "Bian [first=" + first + ",second=" + second + ",value="+ value + "]";}}classShuZu {static ArrayList<ArrayList> list = newArrayList<ArrayList>();// 存搁每一个数组中的节面的数组static ArrayList<ArrayList> bianList = newArrayList<ArrayList>();// 对付应存搁数组中的边的数组public static void check(Bian b)// 查看正在哪个数组中{if (list.size() == 0) {ArrayList<Integer> sub = new ArrayList<Integer>();sub.add(b.getFirst());sub.add(b.getSecond());list.add(sub);ArrayList<Bian> bian = new ArrayList<Bian>();bian.add(b);bianList.add(bian);return;}int first = b.getFirst();int shuyu1 = -1;int second = b.getSecond();int shuyu2 = -1;for (inti = 0; i < list.size(); i++)// 查看二个节面分别属于哪个数组{for (int m = 0; m < list.get(i).size(); m++) {if (first == (Integer) list.get(i).get(m))shuyu1 = i;if (second == (Integer) list.get(i).get(m))shuyu2 = i;}}if (shuyu1 == -1 && shuyu2 == -1)// 表示那二个节面皆不需要新加进{ArrayList<Integer> sub = new ArrayList<Integer>();sub.add(b.getFirst());sub.add(b.getSecond());list.add(sub);ArrayList<Bian> bian = new ArrayList<Bian>();bian.add(b);bianList.add(bian);}if (shuyu1 == -1 && shuyu2 != -1)// 表示有一个面已经正在数组中只把另一个加进便不妨了{list.get(shuyu2).add(first);bianList.get(shuyu2).add(b);}if (shuyu2 == -1 && shuyu1 != -1)// 表示有一个面已经正在数组中只把另一个加进便不妨了{list.get(shuyu1).add(second);bianList.get(shuyu1).add(b);}if (shuyu1 == shuyu2 && shuyu1 != -1)// 表述二个正在共一个组中会产死环{}if (shuyu1 != shuyu2 && shuyu1 != -1 && shuyu2 != -1)// 表示二个面正在分歧的组中需要合并{for (inti = 0; i < list.get(shuyu2).size(); i++) {list.get(shuyu1).add(list.get(shuyu2).get(i));}list.remove(shuyu2);for (inti = 0; i < bianList.get(shuyu2).size(); i++) { bianList.get(shuyu1).add(bianList.get(shuyu2).get(i));}bianList.get(shuyu1).add(b);bianList.remove(shuyu2);}}public static void show() {for (inti = 0; i < bianList.get(0).size(); i++) System.out.println(bianList.get(0).get(i));}}public class Test {public static void main(String[] args) { ArrayList<Bian> l = new ArrayList<Bian>(); l.add(new Bian(1,3,1));l.add(new Bian(1,2,6));l.add(new Bian(1,4,5));l.add(new Bian(2,3,5));l.add(new Bian(2,5,3));l.add(new Bian(3,4,5));l.add(new Bian(3,5,6));l.add(new Bian(3,6,4));l.add(new Bian(4,6,2));l.add(new Bian(5,6,6));Collections.sort(l);// for(inti = 0 ;i<l.size();i++)// System.out.println(l.get(i)); for (inti = 0; i < l.size(); i++) ShuZu.check(l.get(i));ShuZu.show();}}。

最小生成树简单讲解及代码实现

最小生成树简单讲解及代码实现一、Prim算法Prim算法从一个顶点开始,每次选择与当前生成树最近的一个顶点,并添加到生成树中。

该算法依次选择n-1个顶点,直至生成完整的树。

具体步骤如下:1. 假设图G有n个顶点,设置两个数组visited和lowcost,visited用于判断顶点是否已经被访问,lowcost用于记录到已经访问的顶点的最小权重。

2. 选择一个起始顶点,将其标记为已访问,然后根据其邻接顶点的权重更新lowcost数组。

3. 从lowcost数组中选择最小的权重顶点作为下一个访问的节点,并将其标记为已访问。

4. 更新lowcost数组,将其与当前顶点相邻的顶点的权重进行比较,如果低于lowcost数组中对应顶点的权重,则更新。

5.重复步骤3和4,直至所有顶点都被访问。

6. 根据lowcost数组构建最小生成树。

Prim算法的实现代码如下:```pythondef prim(graph):n = len(graph)visited = [False] * nlowcost = [float('inf')] * nlowcost[0] = 0for _ in range(n):minIndex = -1minCost = float('inf')for i in range(n):if not visited[i] and lowcost[i] < minCost:minIndex = iminCost = lowcost[i]visited[minIndex] = Truefor j in range(n):if not visited[j] and graph[minIndex][j] < lowcost[j]: lowcost[j] = graph[minIndex][j]return lowcost```二、Kruskal算法Kruskal算法是一种贪心算法,通过不断地选择边来构建最小生成树。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验报告9 课程 数据结构与算法 实验名称 贪心策略 第 页 班级 11计本 学号 105032011130 姓名 风律澈 实验日期:2013年4月27日 报告退发 (订正 、 重做)

一、实验目的 掌握贪心策略的原理和应用。 二、实验环境 1、微型计算机一台 2、WINDOWS操作系统,Java SDK,Eclipse开发环境

三、实验内容 必做题: 1、编写程序,实现最小生成树prim算法。 2、编写程序,实现最小生成树Kruskal算法。

四、实验步骤和结果 (附上代码和程序运行结果截图) 1,prim

public class main { /** * @param args */ public static final int maxvalue=Integer.MAX_VALUE; public static void main(String[] args) { // TODO Auto-generated method stub int weight[][]={ {0,6,1,5,maxvalue,maxvalue}, {6,0,5,maxvalue,3,maxvalue}, {1,5,0,5,6,4}, {5,maxvalue,5,0,maxvalue,2}, {maxvalue,3,6,maxvalue,0,6}, {maxvalue,maxvalue,4,2,6,0}, }; graph a=new graph(weight); a.showprimtree(); }

} import java.util.ArrayList; import java.util.PriorityQueue; public class graph { private ArrayList vexs;//定义顶点,进入顶点定义初始化 public graph(int weight[][]){ super(); this.vexs=new ArrayList();//生成顶点集对象实例 //start和end是在下面程序中使用以构造边的// vex start; vex end; for(int i=0;i例 this.vexs.add(new vex()); for(int i=0;istart=this.vexs.get(i); for(int j=0;jif(weight[i][j]!=Integer.MAX_VALUE){ end=this.vexs.get(j); new side(start,end,weight[i][j]); } } } }//至此图的所有成分的信息已经完成,返回main public ArrayList prim(){ ArrayList tree=new ArrayList(); PriorityQueue pq=new PriorityQueue(); vex v = this.vexs.get(0); v.setcheck(1); side s; pq.addAll(v.getsides()); while (true) { if(pq.isEmpty())break; s=pq.poll(); if(s.check_intree()==1){ s.un_in(); continue; } v=s.add_tree(); tree.add(s); pq.addAll(v.getsides()); } return tree; } public void showprimtree() { System.out.println(prim()); } } import java.util.ArrayList;

public class vex { private static int ids=0; private int id; private int check; ArrayList sides; public vex(){ super(); id=ids++; check=0; sides=new ArrayList(); } public int getid(){ return id; } public int getcheck(){ return check; } public void setcheck(int i){ this.check=i; } public ArrayList getsides(){ return sides; } public void addside(side s){ this.sides.add(s); } }

public class side implements Comparable{ private vex start; private vex end; private int weight; private int state;//0表示没有动过,1表示处理过,2表示加入树 public side(vex s, vex e, int w) { // TODO Auto-generated constructor stub super(); this.start=s; this.end=e; this.weight=w; this.state=0; s.addside(this); e.addside(this); } public vex add_tree(){ if(this.start.getcheck()==0){ start.setcheck(1); this.state=2; return start; } end.setcheck(1); return end; } public int check_intree(){ if(start.getcheck()+end.getcheck()==2) return 1; return 0; } public int check_idea(){ if (this.state>0) return 1; else return 0; } public void un_in(){ this.state=1; } @Override public int compareTo(side o) { // TODO Auto-generated method stub if(this.weight>o.weight) return 1; if(this.weightreturn 0; } public String toString(){ return "边("+this.start.getid()+","+this.end.getid()+")"; } } 2.kruscal算法 package 最小生成树;

public class main { /** * @param args */ public static final int maxvalue=Integer.MAX_VALUE; public static void main(String[] args) { // TODO Auto-generated method stub int weight[][]={ {0,6,1,5,maxvalue,maxvalue}, {6,0,5,maxvalue,3,maxvalue}, {1,5,0,5,6,4}, {5,maxvalue,5,0,maxvalue,2}, {maxvalue,3,6,maxvalue,0,6}, {maxvalue,maxvalue,4,2,6,0}, }; graph a=new graph(weight); a.showkurscaltree(); }

} package 最小生成树;

import java.util.ArrayList; import java.util.PriorityQueue;

public class graph { private ArrayList vexs;//定义顶点,进入顶点定义初始化 private ArrayList sides; public graph(int weight[][]){ super(); this.vexs=new ArrayList();//生成顶点集对象实例 this.sides=new ArrayList(); //start和end是在下面程序中使用以构造边的// vex start; vex end; for(int i=0;i象实例 this.vexs.add(new vex()); for(int i=0;istart=this.vexs.get(i); for(int j=0;jif(weight[i][j]!=Integer.MAX_VALUE){ end=this.vexs.get(j); this.sides.add(new side(start,end,weight[i][j])); } } } }//至此图的所有成分的信息已经完成,返回main public ArrayList kurscal(){ ArrayList tree=new ArrayList(); PriorityQueue pq=new PriorityQueue(); pq.addAll(this.sides); side s; while (true) { if(pq.isEmpty())break; s=pq.poll(); if(s.together()==1){ tree.add(s); } } return tree; } public void showkurscaltree() { System.out.println(kurscal()); } } package 最小生成树; import java.util.ArrayList;

public class vex { private static int ids=1; private int id;

相关文档
最新文档