实验七 克鲁斯卡算法生成最小树

合集下载

第11周图(下)第2讲-求最小生成树的Kruskal算法

第11周图(下)第2讲-求最小生成树的Kruskal算法

Prim (从v4 开始) :
1:(v1,v4),2:(v1,v3) 或(v3,v4) , 不可能是 (v2,v3)
答案为C
━━本讲完━━
(2)将图G中的边按权值从小到大的顺序依次选取: 若选取的边未使生成树T形成回路,则加入TE; 否则舍弃,直到TE中包含(n-1)条边为止。
0 28 1
10
14
16
5
6
2
24
18
25
12
4
3
22
有条件地加入
0
1
(n-1)条边
5
6
2
4
3
TE={}
Kruskal算法示例的演示
0 28 1
10
14
//k表示当前构造生成树的第几条边 //E中边的下标,初值为0 //生成的边数小于n时循环
{
u1=E[j].u;v1=E[j].v;
//取一条边的头尾顶点
sn1=vset[u1];
sn2=vset[v1]; if (sn1!=sn2)
//分别得到两个顶点所属的集合编号 //两顶点属于不同的集合
{ printf(" (%d,%d):%d\n",u1,v1,E[j].w);
0
33
2 20
在实现克鲁斯卡尔算法Kruskal()时,用数组E存放图G中的所有 边,其类型如下:
typedef struct { int u; //边的起始顶点
int v; //边的终止顶点 int w; //边的权值 } Edge;
Edge E[MAXV];
void Kruskal(MGraph g)
图采用哪种存储结构更合适?
邻接矩阵

最小生成树(Kruskal算法)

最小生成树(Kruskal算法)

三、方案解决:
在本题中我们将采用 Kruskal 算法来构造最小生成树。 从题目所给赋权图中我们可以得到该图的邻接矩阵为:
⎡ 0 20 0 0 0 23 1 ⎤ ⎢20 0 15 0 0 0 4 ⎥ ⎢ ⎥ ⎢ 0 15 0 3 0 0 9 ⎥ ⎢ ⎥ G = ⎢ 0 0 3 0 17 0 16 ⎥ ⎢ 0 0 0 17 0 28 25⎥ ⎢ ⎥ ⎢ 23 0 0 0 28 0 36⎥ ⎢ 1 4 9 16 25 36 0 ⎥ ⎣ ⎦
-3-
6.选择造价第五小的序号为 5 的边,即 S 23 ,由于加入后边 S 23 , S 27 , S37 将构成回路,因此 舍弃该边 如图所示:
7.选择造价第六小的序号为 6 的边,即 S 47 ,由于加入后边 S34 , S37 , S 47 将构成回路,因此 舍弃该边 如图所示:
8.选择造价第七小的序号为 7 的边,即 S 45 ,加入 T 中,此时 T={{6},{ S17 , S34 , S 27 , S37 ,
S 45 , S16 }},Cost=34+23=57
如图所示:
11.算法结束 此时,所有顶点已包含在树中,整棵最小生成树已经构造完成。即应该在城市{(1,7) , (2,7) , (3,7) , (3,4) , (4,5) , (1,6)}之间建造通信道路,可使得城市间相互通信又造价费 用最小,此时可以得到其最小的费用为 57 万元
-7-
edges[k].end = j; edges[k].weight = G->arc[i][j].weight; k++; } } } sort(edges, G); for (i = 1; i <= G->arcnum; i++) { parent[i] = 0; } printf("最小生成树为:\n"); for (i = 1; i <= G->arcnum; i++)//核心部分 { n = Find(parent, edges[i].begin); m = Find(parent, edges[i].end); if (n != m) { parent[n] = m; printf("< %d, %d > %d\n", edges[i].begin, edges[i].end, edges[i].weight); Mincost+=edges[i].weight; } } printf("使各城市间能够通信的最小费用为:Mincost=%d\n",Mincost); } int Find(int *parent, int f) { while ( parent[f] > 0) { f = parent[f]; } return f; }

② kruskal最小生成树算法的定义和实现

② kruskal最小生成树算法的定义和实现

Krskal最小生成树算法是一种用来解决图论中最小生成树问题的算法。

它采用了一种贪心的策略,即每一步都选择权值最小的边,并且保证选择的边不会构成环,直到生成一棵最小生成树为止。

1. 算法的定义kruskal最小生成树算法的定义如下:输入:一个连通无向图G=(V,E),其中V是顶点集合,E是边的集合,每条边都有一个权值。

输出:G的最小生成树算法步骤:① 将图G的所有边按照权值从小到大进行排序。

② 初始化一个空的边集合T,该集合用来存放最小生成树的边。

③ 依次遍历排序后的边集合,对于每一条边e=(u,v),如果将该边添加到T中不会构成环,则将其添加到T中。

④ 重复步骤③,直到T中的边数等于V-1为止,此时T就是G的最小生成树。

2. 算法的实现下面是kruskal最小生成树算法的具体实现过程:```pythonclass UnionFind:def __init__(self, n):self.parent = [i for i in range(n)]def find(self, x):if self.parent[x] != x:self.parent[x] = self.find(self.parent[x]) return self.parent[x]def union(self, x, y):root_x = self.find(x)root_y = self.find(y)if root_x != root_y:self.parent[root_x] = root_ydef kruskal(graph):edges = []for u in range(len(graph)):for v in range(u+1, len(graph)):if graph[u][v] != 0:edges.append((u, v, graph[u][v])) edges.sort(key=lambda x: x[2])n = len(graph)result = []uf = UnionFind(n)for edge in edges:u, v, weight = edgeif uf.find(u) != uf.find(v):uf.union(u, v)result.append((u, v, weight))if len(result) == n - 1:breakreturn result```以上代码实现了kruskal最小生成树算法,其中使用了UnionFind类来实现并查集的功能,以判断是否构成环。

Kruskal算法计算最小生成树(java)

Kruskal算法计算最小生成树(java)

J avaMan_chen的专栏K ruskal算法计算最小生成树(java)分类: 算法 2012-12-04 17:15 243人阅读 评论(2) 收藏举报kruskalKruskal克鲁斯卡尔最小生成树最小生成树定义:每一个无向图可拆分成多个子图,在这些子图中,如果图的各个顶点没有形成回路,则是图的一颗生成树。

最小生成树的意识是树的相邻节点距离之和最小。

应用场景:张三被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。

张三已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。

为了用最小的消费,他想铺设最短的光纤去连接所有的农场,问要如何实现。

算法实现:有关最小生成树的问题常见的算法有两种,分别是Kruskal(克鲁斯卡尔)算法和Prim(普里姆)算法,本文讲解Kruskal算法的实现Kruskal算法的计算流程大致如下:1.将无向图的边按距离长短递增式排序,放到集合中2.遍历该集合,找出最短的边,加入到结果生成树的集合中3.如果结果生成树出现回路,则放弃这条边4.重新执行步骤2,直至所有顶点被遍历可以看出在每次遍历过程中采用了贪心算法算法实例图:代码实现:Edge类用与封装无向图中每条边的信息public class Edge implements Comparable<Edge>{private String start;private String end;private int distance;public Edge(String start,String end,int distance){this.start=start;this.end=end;this.distance=distance;}public String getStart() {return start;}public void setStart(String start) {this.start = start;}public String getEnd() {return end;}public void setEnd(String end) {this.end = end;}public int getDistance() {return distance;}public void setDistance(int distance) {this.distance = distance;}@Overridepublic String toString() {return start + "->" + end;}@Overridepublic int compareTo(Edge obj) {int targetDis=obj.getDistance();return distance>targetDis?1:(distance==targetDis?0:-1);}}MapBuilder类用于构建数据源(数据源结构如上图所示):public class MapBuilder {public TreeSet<Edge> build(){TreeSet<Edge> edges=new TreeSet<Edge>();edges.add(new Edge("A","B",1));edges.add(new Edge("A","C",4));edges.add(new Edge("A","F",6));edges.add(new Edge("B","D",8));edges.add(new Edge("B","E",3));edges.add(new Edge("C","F",5));edges.add(new Edge("C","E",9));edges.add(new Edge("D","E",7));edges.add(new Edge("D","F",10));edges.add(new Edge("E","F",2));return edges;}public int getPointNum(){return 6;}}Kruskal类用于计算最小生成树public class Kruskal {private Set<String> points=new HashSet<String>();private List<Edge> treeEdges=new ArrayList<Edge>();public void buildTree(){MapBuilder builder=new MapBuilder();TreeSet<Edge> edges=builder.build();int pointNum=builder.getPointNum();for(Edge edge:edges){if(isCircle(edge)){continue;}else{//没有出现回路,将这条边加入treeEdges集合treeEdges.add(edge);//如果边数等于定点数-1,则遍历结束if(treeEdges.size()==pointNum-1){return;}}}}public void printTreeInfo(){int totalDistance=0;for(Edge edge:treeEdges){totalDistance+=edge.getDistance();System.out.println(edge.toString());}System.out.println("总路径长度:"+totalDistance);}private boolean isCircle(Edge edge){int size=points.size();if(!points.contains(edge.getStart())){size++;}if(!points.contains(edge.getEnd())){size++;}if(size==treeEdges.size()+1){return true;}else{points.add(edge.getStart());points.add(edge.getEnd());return false;}}}Main类用于测试Kruskal算法public class Main {public static void main(String[] args) {Kruskal test=new Kruskal();test.buildTree();test.printTreeInfo();}}打印输出:A->BE->FB->EA->CD->E总路径长度:17。

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最⼩⽣成树---普⾥姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)最⼩⽣成树的性质:MST性质(假设N=(V,{E})是⼀个连通⽹,U是顶点集V的⼀个⾮空⼦集,如果(u,v)是⼀条具有最⼩权值的边,其中u属于U,v属于V-U,则必定存在⼀颗包含边(u,v)的最⼩⽣成树)普⾥姆算法(Prim算法)思路:以点为⽬标构建最⼩⽣成树1.将初始点顶点u加⼊U中,初始化集合V-U中各顶点到初始顶点u的权值;2.根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩。

循环n-1次如下操作:(1)从数组lowcost[k]中找到vk到集合U的最⼩权值边,并从数组arjvex[k] = j中找到该边在集合U中的顶点下标(2)打印此边,并将vk加⼊U中。

(3)通过查找邻接矩阵Vk⾏的各个权值,即vk点到V-U中各顶点的权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中以下图为例#include<bits/stdc++.h>using namespace std;#define MAXVEX 100#define INF 65535typedef char VertexType;typedef int EdgeType;typedef struct {VertexType vexs[MAXVEX];EdgeType arc[MAXVEX][MAXVEX];int numVertexes, numEdges;}MGraph;void CreateMGraph(MGraph *G) {int m, n, w; //vm-vn的权重wscanf("%d %d", &G->numVertexes, &G->numEdges);for(int i = 0; i < G->numVertexes; i++) {getchar();scanf("%c", &G->vexs[i]);}for(int i = 0; i < G->numVertexes; i++) {for(int j = 0; j < G->numVertexes; j++) {if(i == j) G->arc[i][j] = 0;else G->arc[i][j] = INF;}}for(int k = 0; k < G->numEdges; k++) {scanf("%d %d %d", &m, &n, &w);G->arc[m][n] = w;G->arc[n][m] = G->arc[m][n];}}void MiniSpanTree_Prim(MGraph G) {int min, j, k;int arjvex[MAXVEX]; //最⼩边在 U集合中的那个顶点的下标int lowcost[MAXVEX]; // 最⼩边上的权值//初始化,从点 V0开始找最⼩⽣成树Tarjvex[0] = 0; //arjvex[i] = j表⽰ V-U中集合中的 Vi点的最⼩边在U集合中的点为 Vjlowcost[0] = 0; //lowcost[i] = 0表⽰将点Vi纳⼊集合 U ,lowcost[i] = w表⽰ V-U中 Vi点到 U的最⼩权值for(int i = 1; i < G.numVertexes; i++) {lowcost[i] = G.arc[0][i];arjvex[i] = 0;}//根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩for(int i = 1; i < G.numVertexes; i++) {min = INF, j = 1, k = 0;//寻找 V-U到 U的最⼩权值minfor(j; j < G.numVertexes; j++) {// lowcost[j] != 0保证顶点在 V-U中,⽤k记录此时的最⼩权值边在 V-U中顶点的下标if(lowcost[j] != 0 && lowcost[j] < min) {min = lowcost[j];k = j;}}}printf("V[%d]-V[%d] weight = %d\n", arjvex[k], k, min);lowcost[k] = 0; //表⽰将Vk纳⼊ U//查找邻接矩阵Vk⾏的各个权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中for(int i = 1; i < G.numVertexes; i++) {if(lowcost[i] != 0 && G.arc[k][i] < lowcost[i]) {lowcost[i] = G.arc[k][i];arjvex[i] = k;}}}int main() {MGraph *G = (MGraph *)malloc(sizeof(MGraph));CreateMGraph(G);MiniSpanTree_Prim(*G);}/*input:4 5abcd0 1 20 2 20 3 71 2 42 3 8output:V[0]-V[1] weight = 2V[0]-V[2] weight = 2V[0]-V[3] weight = 7最⼩总权值: 11*/时间复杂度O(n^2)克鲁斯卡尔算法(Kruskal算法)思路:以边为⽬标进⾏构建最⼩⽣成树在边集中依次寻找最⼩权值边,若构建是不形成环路(利⽤parent数组记录各点的连通分量),则将其添加到最⼩⽣成树中。

最小生成树kruskal算法python代码解析

最小生成树kruskal算法python代码解析

最小生成树kruskal算法python代码解析Krulskal算法是一种常用于计算最小生成树的算法,主要用于求解无向带权图的最小生成树。

下面我们来了解一下Krulskal算法的具体实现方法。

算法设计思路Krulskal算法的实现主要通过以下几个步骤:1. 初始化:对于给定的图G,首先需要把图中所有的边按照权重大小从小到大排序,然后初始化一个空的边集合T。

2. 遍历:按照边的权重从小到大的顺序遍历所有的边。

3. 判定:对于当前遍历到的边,如果这条边的两个端点不在同一个连通块中,那么就将这条边加入到集合T中,同时将这两个端点所在的连通块合并成一个连通块。

4. 输出:最终输出的集合T即为图G的最小生成树。

代码解析下面给出Krulskal算法的Python代码实现。

1. 初始化```def init(graph):edges = []nodes = set()for start in graph:nodes.add(start)for end, weight in graph[start]:edges.append((start, end, weight))edges = sorted(edges, key=lambda e: e[2]) # 对边按照权重排序 return edges, nodes```在初始化中,我们将图G中所有的边按照权重大小从小到大排序,同时用一个set集合来存储所有的节点,方便后面的查找。

2. 遍历```def kruskal(graph):edges, nodes = init(graph)tree_edges = []disjoint_sets = [{node} for node in nodes]for start, end, weight in edges:start_set = find_set(disjoint_sets, start)end_set = find_set(disjoint_sets, end)if start_set != end_set:tree_edges.append((start, end))merge_sets(disjoint_sets, start_set, end_set)return tree_edges```在这一步中,我们按照边的权重从小到大的顺序遍历所有的边,同时查找每条边的两个端点所在的连通块。

数学建模-最小生成树-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上的那个。

非常清晰且直观。

首先第一步,我们有一张图,有若干点和边如下图所示:第一步我们要做的事情就是将所有的边的长度排序,用排序的结果作为我们选择边的依据。

最小生成树算法(克鲁斯卡尔算法和普里姆算法)

最⼩⽣成树算法(克鲁斯卡尔算法和普⾥姆算法)⼀般最⼩⽣成树算法分成两种算法:⼀个是克鲁斯卡尔算法:这个算法的思想是利⽤贪⼼的思想,对每条边的权值先排个序,然后每次选取当前最⼩的边,判断⼀下这条边的点是否已经被选过了,也就是已经在树内了,⼀般是⽤并查集判断两个点是否已经联通了;另⼀个算法是普⾥姆算法:这个算法长的贼像迪杰斯塔拉算法,⾸先选取⼀个点进⼊集合内,然后找这个点连接的点⾥⾯权值最⼩的点,然后每次在选取与集合内任意⼀点连接的点的边的权值最⼩的那个(这个操作可以在松弛那⾥修改⼀下,这也是和迪杰斯塔拉算法最⼤的不同,你每次选取⼀个点后,把这个点能达到的点的那条边的权值修改⼀下,⽽不是像迪杰斯塔拉算法那样,松弛单点权值);克鲁斯卡尔代码:#include<iostream>#include<algorithm>#define maxn 5005using namespace std;struct Node{int x;int y;int w;}node[maxn];int cmp(Node x,Node y){return x.w<y.w;}int fa[maxn];int findfa(int x){if(fa[x]==x)return x;elsereturn findfa(fa[x]);}int join(int u,int v){int t1,t2;t1=findfa(u);t2=findfa(v);if(t1!=t2){fa[t2]=t1;return1;}elsereturn0;}int main(){int i,j;int sum;int ans;int n,m;sum=0;ans=0;cin>>n>>m;for(i=1;i<=m;i++)cin>>node[i].x>>node[i].y>>node[i].w;sort(node+1,node+1+m,cmp);for(i=1;i<=n;i++)fa[i]=i;for(i=1;i<=m;i++){if(join(node[i].x,node[i].y)){sum++;ans+=node[i].w;}if(sum==n-1)break;}cout<<ans<<endl;return0;}普⾥姆算法:#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#define inf 0x3f3f3fusing namespace std;int Map[1005][1005];int dist[1005];int visit[1005];int n,m;int prime(int x){int temp;int lowcast;int sum=0;memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++)dist[i]=Map[x][i];visit[x]=1;for(int i=1;i<=n-1;i++){lowcast=inf;for(int j=1;j<=n;j++)if(!visit[j]&&dist[j]<lowcast){lowcast=dist[j];temp=j;}visit[temp]=1;sum+=lowcast;for(int j=1;j<=n;j++){if(!visit[j]&&dist[j]>Map[temp][j]) dist[j]=Map[temp][j];}}return sum;}int main(){int y,x,w,z;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==j)Map[i][j]=0;elseMap[i][j]=inf;}}memset(dist,inf,sizeof(dist)); for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&w); Map[x][y]=w;Map[y][x]=w;}z=prime(1);printf("%d\n",z);return0;}。

kruskal算法求最小生成树

kruskal算法求最小生成树课题:用kruskal算法求最小生成树。

编译工具:Visual Studio 2017kruskal算法基本思想:先构造一个只含n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集E中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。

依次类推,直到森林中只有一棵树,也即子图中含有n-1 条边为止。

问题:按如下连通图用kruskal算法求最小生成树。

程序源码:#include <iostream>#include <algorithm>using namespace std;const int N = 100;int nodeset[N];int n, m;struct Edge { //定义结构体.int u;int v;int w;}e[N*N];bool comp(Edge x, Edge y) { //配合sort()方法对权值进行升序。

return x.w < y.w;}void Init(int n) //对集合号nodeset数组进行初始化. {for (int i = 1; i <= n; i++)nodeset[i] = i;}int Merge(int a, int b) //将e[i].u结点传递给a; e[i].v结点传递给b. {int p = nodeset[a]; //p为a结点的集结号,int q = nodeset[b]; //q为b 结点的集结号.if (p == q) return 0; //判断结点间是否回环。

若两个结点的集结号相同,则不操作,直接返回。

for (int i = 1; i <= n; i++)//若两个结点的集结号不相同,检查所有结点,把集合号是q的改为p.{if (nodeset[i] == q)nodeset[i] = p;}return 1;}int Kruskal(int n){int ans = 0;for (int i = 1; i<=m; i++)if (Merge(e[i].u, e[i].v)){cout << "A结点:" << e[i].u << "一>B结点:" << e[i].v << endl; //输出满足条件的各结点ans += e[i].w;n--;if (n == 1)return ans;}return 0;}int main() {cout << "输入总结点数(n)和总边数(m):" << endl;cin >> n >> m;Init(n);cout << "输入结点数(u),(v)和权值(w):" << endl;for (int i = 1; i <= m; i++)cin >> e[i].u >> e[i].v >> e[i].w;sort(e+1, e + m+1, comp);int ans = Kruskal(n);cout << "最小的花费是:" << ans << endl;return 0;}源码流程解析:(1)在main()中,输入结点数n与边m,n=7,m=12。

数学建模-最小生成树-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上的那个。

非常清晰且直观。

首先第一步,我们有一张图,有若干点和边如下图所示:第一步我们要做的事情就是将所有的边的长度排序,用排序的结果作为我们选择边的依据。

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

实验七 图的应用---最小生成树问题
-----克鲁斯卡尔算法
一、实验目的
1、使学生可以巩固所学的有关图的基本知识。
2、熟练掌握图的存储结构。
3、掌握如何应用图解决各种实际问题。
[问题描述]
若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。如何以最
低的经济代价建设这个通信网,是一个网的最小生成树问题。
[基本要求]
1.利用克鲁斯卡尔算法求网的最小生成树。
2.要求输出各条边及它们的权值。

6 1
5
2
3 4

二、测试结果
最小生成树

1
5
2
3 4

1
2
4

3

6
5

1
2
4

3

6
5
三、程序代码
#include
#include
#define MAX_VERTEX_NUM 20
typedef int VertexType;
typedef int QElemType;
typedef int InfoType;

/****************************** 结构体部分 ****************************/
typedef struct ArcNode
{
int adjvex; //该弧指向的顶点的位置
struct ArcNode *nextarc; //指向下一条弧的指针
InfoType *info; //该弧相关信息指针
}ArcNode;

typedef struct VNode
{
VertexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附于该顶点的指针
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct
{
AdjList vertices;
int vexnum,arcnum; //弧的顶点数和弧数
int kind; //弧的类型
}ALGraph;

typedef int VRType;
typedef struct
{
int begin,end;
VRType cost;
}EDGE;

/****************************** 函数操作部分 ****************************/
void Swapn(EDGE *edges,int i,int j)
{
int temp;
temp=edges[i].begin;
edges[i].begin=edges[j].begin;
edges[j].begin=temp;
temp=edges[i].end;
edges[i].end=edges[j].end;
edges[j].end=temp;
temp=edges[i].cost;
edges[i].cost=edges[j].cost;
edges[j].cost=temp;
}

void Sort(EDGE *edges,ALGraph G)
{
int i,j;
for(i=1;i<=G.vexnum;++i)
for(j=i;j<=G.vexnum;++j)
if(edges[i].cost>edges[j].cost)
Swapn(edges,i,j);
}

int Find(int *parents,int f)
{
while(parents[f]>0)
f=parents[f];
return (f);
}

void MiniSpanTree_Kruskal(ALGraph G)
{
int i,v1,v2,value,bnf,edf;
int parents[MAX_VERTEX_NUM];
EDGE edges[MAX_VERTEX_NUM];
printf("请输入顶点和边的数量:\n");
scanf("%d%d",&G.vexnum,&G.arcnum);
for(i=1;i<=G.arcnum;++i)
{
printf("请输入第%d条边的两个顶点和权值:\n",i);
scanf("%d%d%d",&v1,&v2,&value);
edges[i].begin=v1;
edges[i].end=v2;
edges[i].cost=value;
}
Sort(edges,G);
for(i=1;i<=G.vexnum;++i)
parents[i]=0;
printf("\n结果是:\n");
for(i=1;i<=G.vexnum;++i)
{
bnf=Find(parents,edges[i].begin);
edf=Find(parents,edges[i].end);
if(bnf!=edf)
{
parents[bnf]=edf;
printf("Arc(%d,%d):%d\n",edges[i].begin,edges[i].end,edges[i].cost);
}
}
}

/****************************** 主函数部分 ****************************/
void main()
{
ALGraph G;
MiniSpanTree_Kruskal(G);
}

相关文档
最新文档