最小生成树

合集下载

最小生成树 实验报告

最小生成树 实验报告

最小生成树实验报告最小生成树实验报告一、引言最小生成树是图论中的一个重要概念,它在实际问题中有着广泛的应用。

本次实验旨在通过编程实现最小生成树算法,并通过实验数据对算法进行分析和评估。

二、算法介绍最小生成树算法的目标是在给定的带权无向图中找到一棵生成树,使得树上所有边的权重之和最小。

本次实验我们选择了两种经典的最小生成树算法:Prim 算法和Kruskal算法。

1. Prim算法Prim算法是一种贪心算法,它从一个顶点开始,逐步扩展生成树的规模,直到包含所有顶点为止。

算法的具体步骤如下:(1)选择一个起始顶点,将其加入生成树中。

(2)从与生成树相邻的顶点中选择一个权重最小的边,将其加入生成树中。

(3)重复上述步骤,直到生成树包含所有顶点。

2. Kruskal算法Kruskal算法是一种基于并查集的贪心算法,它首先将图中的边按权重从小到大进行排序,然后逐个加入生成树中,直到生成树包含所有顶点为止。

算法的具体步骤如下:(1)将图中的边按权重从小到大进行排序。

(2)逐个加入边,如果该边的两个顶点不在同一个连通分量中,则将其加入生成树中。

(3)重复上述步骤,直到生成树包含所有顶点。

三、实验过程本次实验我们使用C++语言实现了Prim算法和Kruskal算法,并通过随机生成的图数据进行了测试。

1. Prim算法的实现我们首先使用邻接矩阵表示图的结构,然后利用优先队列来选择权重最小的边。

具体实现过程如下:(1)创建一个优先队列,用于存储生成树的候选边。

(2)选择一个起始顶点,将其加入生成树中。

(3)将与生成树相邻的顶点及其边加入优先队列。

(4)从优先队列中选择权重最小的边,将其加入生成树中,并更新优先队列。

(5)重复上述步骤,直到生成树包含所有顶点。

2. Kruskal算法的实现我们使用并查集来维护顶点之间的连通关系,通过排序后的边序列来逐个加入生成树中。

具体实现过程如下:(1)将图中的边按权重从小到大进行排序。

的最小生成树算法Prim与Kruskal算法的比较

的最小生成树算法Prim与Kruskal算法的比较

的最小生成树算法Prim与Kruskal算法的比较Prim算法和Kruskal算法都是常用的最小生成树算法,它们可以在给定的加权连通图中找到连接所有节点的最小权重边集合。

然而,这两种算法在实现细节和时间复杂度上有所不同。

本文将对Prim算法和Kruskal算法进行比较,并讨论它们的优缺点以及适用场景。

一、Prim算法Prim算法是一种贪心算法,它从一个起始节点开始,逐步扩展最小生成树的边集合,直到包含所有节点为止。

具体步骤如下:1. 选取一个起始节点作为最小生成树的根节点。

2. 在最小生成树的边集合中寻找与当前树集合相连的最小权重边,并将这条边添加到最小生成树中。

3. 将新添加的节点加入到树集合中。

4. 重复步骤2和3,直到最小生成树包含所有节点为止。

Prim算法的时间复杂度为O(V^2),其中V是节点的个数。

这是因为在每轮迭代中,需要从树集合以外的节点中找到与树集合相连的最小权重边,而在最坏情况下,可能需要检查所有的边。

二、Kruskal算法Kruskal算法是一种基于边的贪心算法,它按照边的权重从小到大的顺序依次选择边,并判断是否加入最小生成树中。

具体步骤如下:1. 初始化一个空的最小生成树。

2. 将所有边按照权重从小到大进行排序。

3. 依次检查每条边,如果这条边连接了两个不同的树(即不会形成环),则将这条边加入到最小生成树中。

4. 重复步骤3,直到最小生成树包含所有节点为止。

Kruskal算法使用并查集数据结构来快速判断连通性,时间复杂度为O(ElogE),其中E是边的个数。

排序边的时间复杂度为O(ElogE),而对每条边进行判断和合并操作的时间复杂度为O(E)。

三、比较与总结1. 时间复杂度:Prim算法的时间复杂度为O(V^2),而Kruskal算法的时间复杂度为O(ElogE)。

因此,在边的数量较大的情况下,Kruskal 算法的效率优于Prim算法。

2. 空间复杂度:Prim算法需要维护一个大小为V的优先队列和一个大小为V的布尔数组,而Kruskal算法需要维护一个大小为V的并查集。

运筹学最小生成树破圈法例题

运筹学最小生成树破圈法例题

运筹学最小生成树破圈法例题引言运筹学是一门研究如何优化决策的学科,它可以帮助我们在面对各种约束条件和目标函数的情况下,找到一个最优解。

其中一个重要的问题是最小生成树(Minimum Spanning Tree,MST)问题,它用于解决图论中的连通性问题。

在本文中,我们将重点讨论用破圈法(Cycle Breaking Algorithm)求解最小生成树问题的例题。

什么是最小生成树问题?最小生成树问题是在一个加权连通图中,找到一个边的子集,使得这个子集形成一棵树,并且这棵树上所有边的权重之和最小。

最小生成树问题常被用于网络设计、电力传输、通信网络等领域。

最小生成树破圈法为了解决最小生成树问题,我们介绍一种常用的算法——破圈法。

该算法的基本思想是不断将新的边加入到当前的生成树中,同时保证生成树中不会形成闭合的回路。

下面通过一个例题来详细介绍破圈法的具体步骤。

例题描述假设我们有一个无向连通图,共有6个顶点,边的权重如下表所示:边权重AB 4AD 6AC 5BC 1BD 2BE 3CE 7DE 8DF 9边权重EF 10我们的目标是找到这个图的最小生成树。

破圈法求解步骤以下是破圈法求解最小生成树问题的具体步骤:1.初始化:选择一个起始顶点作为生成树的根节点,将该顶点加入生成树的顶点集合V’中,将该顶点的所有相邻边加入到候选边集合E’中,并按权重从小到大排序。

2.迭代:从候选边集合E’中选择一条权重最小且不会形成回路的边e,将该边的两个顶点加入到顶点集合V’中,并将这条边加入生成树的边集合中。

同时更新候选边集合,将与新加入顶点有关的边加入候选边集合,并按权重排序。

3.终止条件:重复步骤2,直到生成树包含了全部的n-1个顶点,其中n为原图的顶点个数。

破圈法求解最小生成树例题解析根据以上步骤,我们逐步求解例题中给出的图的最小生成树。

Step 1: 初始化我们选择顶点A作为起始顶点,并将其加入生成树的顶点集合V’中。

最小生成树名词解释

最小生成树名词解释

最小生成树名词解释
最小生成树是一种用于解决图论中最小连接问题的算法,它在一个给定的连通图中寻找一个子图,该子图包含所有顶点,且边的权重之和最小。

在最小生成树中,只有图中的一部分边被选中,以连接图中的所有顶点,并且这些边的权重之和最小。

换句话说,最小生成树是图中的一棵树,它连接了图中的所有顶点,并且其边的权重之和最小。

最小生成树经常被应用于网络设计、城市规划、电网建设等领域。

通过找到最小生成树,可以有效地构建具有最小成本的网络或路线,并优化资源的分配。

常见的最小生成树算法有Prim算法和Kruskal算法,它们通过不同的策略来选择连接顶点的边,最终得到最小生成树。

最小生成树的概念和应用在实际生活中具有重要意义,可以帮助优化各种资源的利用和规划。

实验5最小生成树算法的设计与实现(报告)

实验5最小生成树算法的设计与实现(报告)

实验5 最小生成树算法的设计与实现一、实验目的1、根据算法设计需要, 掌握连通图的灵活表示方法;2、掌握最小生成树算法,如Prim、Kruskal算法;3、基本掌握贪心算法的一般设计方法;4、进一步掌握集合的表示与操作算法的应用。

二、实验内容1、认真阅读算法设计教材和数据结构教材内容, 熟习连通图的不同表示方法和最小生成树算法;2、设计Kruskal算法实验程序。

有n个城市可以用(n-1)条路将它们连通,求最小总路程的和。

设计测试问题,修改并调试程序, 输出最小生成树的各条边, 直至正确为止。

三、Kruskal算法的原理方法边权排序:1 3 14 6 23 6 41 4 52 3 53 4 52 5 61 2 63 5 65 6 61. 初始化时:属于最小生成树的顶点U={}不属于最小生成树的顶点V={1,2,3,4,5,6}2. 根据边权排序,选出还没有连接并且权最小的边(1 3 1),属于最小生成树的顶点U={1,3},不属于最小生成树的顶点V={2,4,5,6}3. 根据边权排序,选出还没有连接并且权最小的边(4 6 2),属于最小生成树的顶点U={{1,3},{4,6}}(还没有合在一起,有两颗子树),不属于最小生成树的顶点V={2,5}4. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,3,4,6}(合在一起),不属于最小生成树的顶点V={2,5}5. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,6},,不属于最小生成树的顶点V={5}6. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,5,6}此时,最小生成树已完成四、实验程序的功能模块功能模块:bool cmp(Edge a,Edge b); //定义比较方法x);//在并查集森林中找到x的祖先int g etfa(intint s ame(int x,int y); //判断祖先是否是同一个,即是否联通 void merge(int x,int y); //合并子树,即联通两子树sort(e+1,e+m+1,cmp); //对边按边权进行升序排序详细代码:#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define M AXN_E 100000#define M AXN_V 100000using namespace std;struct Edge{int f m,to,dist;//边的起始顶点,边的到达顶点,边权}e[MAXN_E];int f a[MAXN_V],n,m; //顶点数组,顶点总数,边总数 //定义比较,只是边权比较bool cmp(Edge a,Edge b){return a.dist < b.dist;}//查找x的祖先是在并查集森林中找到x的祖先x){//getfaint g etfa(intreturn fa[x];if(fa[x]==x)else r eturn fa[x] = getfa(fa[x]);}//判断祖先是否是同一个,即是否联通int s ame(int x,int y){return getfa(x)==getfa(y);}//合并两棵树void merge(int x,int y){int f ax=getfa(x),fay=getfa(y);fa[fax]=fay;}int m ain(){int i;cout<<"请输入顶点数目和边数目:"<<endl;cin>>n>>m;//n为点数,m为边数//输出顶点信息cout<<"各个顶点值依次为:"<<endl;for(i=0;i<n;i++){fa[i]=i;if(i!=0)cout<<fa[i]<<" ";}cout<<endl;cout<<"请输入边的信息(例子:1 4 5 从顶点1到顶点4的边权为5)"<<endl;for(i=1;i<=m;i++)用边集数组存放边,方便排序和调用 cin>>e[i].fm>>e[i].to>>e[i].dist;//sort(e+1,e+m+1,cmp); //对边按边权进行升序排序表示目前的点共存在于多少个集合中,初始情况是每 int r st=n,ans=0;//rst个点都在不同的集合中for(i=1;i<=m && rst>1;i++){int x=e[i].fm,y=e[i].to;函数是查询两个点是否在同一集合中 if(same(x,y))continue;//sameelse{函数用来将两个点合并到同一集合中 merge(x,y);//mergerst--;//每次将两个不同集合中的点合并,都将使rst值减1这条边是最小生成树中的边,将答案加上边权 ans+=e[i].dist;//}}cout<<ans;return 0;}五、测试数据和相应的最小生成树Input:6 101 2 61 3 11 4 52 3 52 5 63 4 53 5 63 6 44 6 25 6 6Putout:18生成树为:七、思考题1、微软面试题一个大院子里住了50户人家,每家都养了一条狗,有一天他们接到通知说院子里有狗生病了,并要求所有主人在发现自己家狗生病的当天就要把狗枪杀掉。

最小生成树---普里姆算法(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数组记录各点的连通分量),则将其添加到最⼩⽣成树中。

最小生成树问题例题

最小生成树问题例题

最小生成树问题例题最小生成树(Minimum Spanning Tree)是图论中的一个经典问题,它是指在一个带权无向图中找到一棵生成树,使得树上所有边的权值之和最小。

最小生成树问题在实际生活中有着广泛的应用,比如电力输送、通信网络等领域。

下面我们以一个具体的例子来说明最小生成树问题的求解过程。

假设有一个无向图,图中包含了6个节点(A、B、C、D、E、F)和9条边。

每条边都有一个权值,表示连接两个节点的成本。

我们的目标是找到一棵最小生成树。

首先,我们可以使用 Prim 算法来求解最小生成树。

Prim 算法的基本思想是从一个起始节点开始,逐步扩展生成树,直到包含所有节点为止。

具体步骤如下:1. 选择一个起始节点,将其标记为已访问。

2. 从已访问的节点中,选择一条连接到未访问节点的最短边。

3. 将这条边加入到最小生成树中,并将连接的节点标记为已访问。

4. 重复步骤2和步骤3,直到所有节点都被访问过。

根据上述算法,我们可以依次选取边 AB、CD、BC、EF、DE 来构建最小生成树。

最终的最小生成树是:A-B、C-D、B-C、E-F 和 D-E 这五条边,它们的权值之和为12。

另外一个常用的求解最小生成树问题的算法是 Kruskal 算法。

Kruskal 算法的基本思想是将图中的边按照权值从小到大进行排序,然后依次选取边,如果这条边连接的两个节点不在同一个连通分量中,就将这条边加入到最小生成树中。

具体步骤如下:1. 对图中的边按照权值进行排序。

2. 从权值最小的边开始,依次选取边。

3. 如果选取的边连接的两个节点不在同一个连通分量中,就将这条边加入到最小生成树中,并将连接的节点合并为一个连通分量。

4. 重复步骤2和步骤3,直到最小生成树中包含了所有的节点。

使用 Kruskal 算法求解上述例子,我们可以依次选取边 AB、BC、CD、DE、EF 来构建最小生成树。

最终的最小生成树是:A-B、B-C、C-D、D-E 和 E-F 这五条边,它们的权值之和也是12。

最小生成树唯一的充要条件

最小生成树唯一的充要条件

最小生成树唯一的充要条件最小生成树是一种在图论中常见的概念,它是一个连通无向图中的一棵生成树,其所有边的权值之和最小。

在实际应用中,最小生成树有着广泛的应用,比如在通信网络、电力网络和交通运输等领域。

要确定一个图的最小生成树是否唯一,需要满足以下充要条件:图中的每条边的权值互不相同。

这个条件是非常重要的,因为只有当图中的每条边的权值都不相同时,才能确保最小生成树的唯一性。

如果图中存在两条或多条边的权值相同,那么可能会有多个最小生成树。

为了更好地理解最小生成树唯一的充要条件,我们可以通过一个简单的例子来说明。

假设有一个无向图,其中包含4个顶点A、B、C、D,以及4条边AB、AC、BC、BD。

如果这些边的权值分别为1、2、3、4,那么根据最小生成树的算法,我们可以得到唯一的最小生成树,即连接顶点A、B、C的边AB、AC。

因为在这种情况下,每条边的权值都不相同,所以最小生成树是唯一的。

相反,如果图中存在两条或多条边的权值相同,那么就会出现多个最小生成树的情况。

比如,如果在上面的例子中,边AC的权值改为1,那么就会有两个最小生成树,一个是连接顶点A、B、C的边AB、AC,另一个是连接顶点A、C、D的边AC、CD。

这是因为存在两条权值相同的边AB和AC,所以会有多个最小生成树。

因此,最小生成树的唯一性与图中每条边的权值是否相同密切相关。

只有当图中的每条边的权值都不相同时,最小生成树才是唯一的。

这个充要条件在实际应用中非常重要,因为只有满足这个条件,我们才能准确地求解出最小生成树,从而优化网络结构,提高效率。

最小生成树唯一的充要条件是图中的每条边的权值互不相同。

只有当图中的每条边的权值都不相同时,最小生成树才是唯一的。

这个条件在实际应用中非常重要,因为只有满足这个条件,我们才能准确地求解出最小生成树,从而优化网络结构,提高效率。

希望通过本文的介绍,读者能够更好地理解最小生成树的唯一性条件,为实际应用提供参考。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
16
17
D
应用举例——最小生成树
Prim算法 34 A 46 19 F B 12 26 25 E 38 cost'={(A, B)34, (C, D)17, (F, E)26}
17
U={A, F, C, D}
V-U={B, E}
cost={(A, B)34, (F, E)26}
25
C
17
D
应用举例——最小生成树
{B, C, D, E, F} (A F)19
{B, C, D, E} {B, D, E} {B, E} {B} {}
(F C)25
(C D)17
(F E)26
adjvex lowcost
adjvex lowcost
4 12
{A, F, C, D, E}
{A,F,C,D,E,B}
(E B)12
21
应用举例——最小生成树
Prim算法——伪代码
1. 将顶点0加入集合U中; 2. 初始化辅助数组shortEdge,分别为lowcost和adjvex赋值; 3. 重复执行下列操作n-1次 3.1 在shortEdge中选取最短边,取其对应的下标k; 3.2 输出边(k, shortEdge[k].adjvex)和对应的权值; 3.3 将顶点k加入集合U中; 3.4 调整数组shortEdge;
U
V-U
输出
adjvex lowcost adjvex lowcost adjvex lowcost adjvex lowcost
0 34 0 34 0 34 0 34
0 46 5 25
0 ∞ 5 25 2 17
0 ∞ 5 26 5 26 5 26
0 19
{A} {A, F} {A, F, C} {A, F, C, D}
14
25
C
17
D
应用举例——最小生成树
Prim算法 U={A, F} 34 A 46 19 F B 12 26 25 E 38 V-U={B, C, D, E} cost={(A, B)34, (F, C)25, (F, D)25, (F, E)26}
25
C
17
D
cost'={(A, B)34, (A, C)46, (A, D)∞,(A, E)∞,(A, F)19}
for(i=1;i<n;i++)//n-1次,n为顶点个数 { Min=999999; for(j=0;j<n;j++) { if(Min>lowcost[j]&&!vis[j])//寻找满足一个顶点未加入生成树, 另一个顶点已加入生成树的最小边 { Min=lowcost[j]; pos=j; } } sum+=Min; vis[pos]=1;//将顶点pos加入生成树 for(j=0;j<n;j++)//更新由顶点pos到其他未加入生成树的顶点 边的权值 { if(lowcost[j]>map[pos][j]&&!vis[j]) lowcost[j]=map[pos][j]; } }
最小生成树
生成树是一个连通图G的一个极小连通子 图。包含G的所有n个顶点,但只有n-1条 边,并且是连通的。

当生成树中所包含的边的权值和最小, 我们称之为最小生成树。
最小生成树性质
最小生成树的边数必然是顶点数减一,|E| = |V| - 1。 最小生成树不可以有循环。 最小生成树不必是唯一的。


本节所介绍的2种最小生成树算法,都是 基于贪心策略。 I.Kruskal算法 II.Prim算法
应用举例——最小生成树
克鲁斯卡尔(Kruskal)算法
基本思想:
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁 斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶 点,而边集为空的子图,若将该子图中各个顶点看成是各棵树 上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网 的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属 不同的树,则将其加入子图,也就是说,将这两个顶点分别所 在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同 一棵树上,则不可取,而应该取下一条权值最小的边再试之。 依次类推,直至森林中只有一棵树,也即子图中含有 n-1 条边 为止。
如何用lowcost和adjvex表示候选最短边集?
shortEdge[i].lowcost=w 表示顶点vi和vk之间权值为w, shortEdge[i].adjvex=k 其中:vi∈ V-U 且vk ∈U
20
应用举例——最小生成树
i
数组
B(i=1) C(i=2) D(i=3) E(i=4) F(i=5)
1. 初始化: U={u0}(u0∈V),TE={ }; 2. 循环直到U=V为止 2.1 在所有u∈U,v∈V-U的边中找一条代价最小的边(u,v); 2.2 TE=TE+{(u,v)}; 2.3 U=U+{v}; 12
应用举例——最小生成树
普里姆(Prim)算法 关键:是如何找到连接U和V-U的最短边。 利用MST性质,可以用下述方法构造候选最短边集: 对V-U中的每个顶点,分别求其到U的最短边。
MST性质
假设 G=(V, E) 是一个无向连通网, U是顶点集 V的一 个非空子集。若 (u, v)是一条具有最小权值的边,其 中u∈U, v∈V-U,则必存在一棵包含边(u, v)的最 小生成树。
T1 顶 点 集 U u' u T2 v
v'
顶 点 集 V-U
11
应用举例——最小生成树
普里姆(Prim)算法
基本思想:设 G=(V, E) 是具有 n 个顶点的连通网, T=(U, TE) 是 G 的 最 小 生 成 树 , T 的 初 始 状 态 为 U={u0} ( u0∈V ), TE={ } ,重复执行下述操作: 在所有 u∈U , v∈V-U 的边中找一条代价最小的边 (u, v)并入集合TE,同时v并入U,直至U=V。
T1
顶 点 集 U u T2 v 顶 点 集 V-U
u'
13
应用举例——最小生成树
Prim算法 34 A 46 19 F B 12 26 25 E 38 U={A}
V-U={B, C, D, E, F}
cost={(A, B)34, (A, C)46, (A, D)∞, (A, E)∞, (A, F)19}
bool Union(int a,int b,int d)//合并 { if(a==b) return 0;//a==b说明边的两个顶点一属于同一颗树, 所以不需要合并,直接返回 root[a]=b;//将a的父节点更新为b,从而将树a,b合并成一棵树 s+=d;//将边的权值加到s当中 return 1; } void kruskal() { for(int i=0;i<n;i++)//初始化,将各顶点的父节点标记为本身 root[i]=i; sort(edge,edge+m,cmp);//将所有边 根据边的权值 从小到大排列 s=0; for(i=0;i<m;i++)//遍历所有的边 { if(Union(find(edge[i].a),find(edge[i].b),edge[i].d)) n--;//当合并成功,森林的树就少一棵 }//当遍历完所有的边时,如果n!=1,说明该无向图不是连通图,不存在最小生成树 }
Kruskal 算法过程
8 4 a 8 h 1 g 2 f b 2 i 7 6 10 c
7
d
9 e
11
4
14
两点属于 同一颗树 两点属于 同一颗树
两点属于同 一颗树
当森林只剩下一 棵树时,算法结 束
#include<iostream> #include<algorithm> using namespace std; struct Edge { int a,b;//边的两个顶点的编号 int d;//边的权值 }edge[11111]; int n,m,s;//n为无向图的顶点个数,m为边的条数,s用来存放最小生成树的总权值 int root[111];//存储父节点 bool cmp(Edge a,Edge b) { return a.d<b.d; } int find(int a)//寻找父节点 { if(root[a]==a) return a; return root[a]=find(root[a]); }
Prim 算法过程
8 4 a 8 h 1 g 2 f b 2 i 7 6 10 c 7
d
9 e
11
4
14
全部节点都被覆 盖,算法结束
//数组lowcost[n]:用来保存非生成树中各顶点与生成树中顶点最短边的权值; //数组vis[n]:用来表示顶点v是否已加入最小生成树中。 int pos=0;sum=0;//sum用来存放最小生成树的总权值 for(i=0;i<n;i++)// { //map[0][i]:选取编号为0的顶点加入最小生成树中 lowcost[i]=map[0][i];//将其余各顶点到编号0顶点的权值存储到lowcost当中 vis[i]=0;//起始状态,所有点都未加入到最小生成树中 } vis[0]=1;//编号为0的顶点加入最小生成树中
22
Prim算法流程



定义一个点的集合S,集合内的点都是当前所 形成的生成树可以到达的。一个点到集合S的 距离定义为连结这个点和任意一个集合S内点 的边的最小权值。 1.初始化,将任意一点加入集合S。 2.选取含当前未入集合S的点到集合S的最短距 离的边,将其加入导出子图,将此点加入集合 S,并更新周围点到集合S的距离。 3.重复2过程|V|-1次。 4.所形成的导出子图就是一棵最小生成树
相关文档
最新文档