关于最小生成树问题

我们通过一个例子来看一下最小生成树的求法。

分别用普里姆算法(从A结点开始)和克鲁斯卡尔算法计算下图的最小生成树。

ok,首先运用Prim算法进行计算:

U V-U B C D E F TE
{A} {B,C,D,E,F} AB

11

AC

13

~

AE

16

~

AB

11

{A,B} {C,D,E,F}   BC

7

BD

3

AE

16

BF

5

BD

3

{A,B,D} {C,E,F}   BC

7

  AE

16

BF

5

BF

5

{A,B,D,F} {C,E}   BC

7

  FE

12

  BC

7

{A,B,D,F,C} {E}       FE

12

  FE

12

{A,B,D,F,C,E} {}            

图表可能看着有点乱,没关系,我们先来看一下Prim算法的基本思想:假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:在所有u∈U, v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。

那么对照例图和表格我们就很容易地可以看出该算法的计算流程,首先从结点A开始,分别写出与其他结点的路径和权值,如果不连通则取权值为无穷,于是就有了表格的第二行,TE取代价最小的AB;然后将B添加到U,写出结点B与其他结点的路径和相应的权值,当然A就不用再写了,大家可以看到,凡是添加到最小生成树中的路径,之后该列则为空,因为它已经是代价最小的边,不可能再有其他边比它更小了;还有一个问题。为了方便起见,在同一列中,如果对应边的权值不小于其前一个,则将其直接落下来,这样就可以只比较那个“更小的”,这样就不用每一行都去比较了;按照这个思路,表格的第三行,BD的权值为3,小于其前一个的权值无穷,则写入3;第五行,FE的权值为12,小于其前一个AE的权值16,所以写入12;其实每一行和每一列都是在找那个代价最小的路径,这样求得的集合就是最小生成树,当然还得加入结点的集合,这样所示表格也就不难理解了,每一行找到一条代价最小的路径,加入TE,然后将结点加入U,再去比较其他的路径,就这样一直走下去,最后得到最小生成树集合。

接下来进入克鲁斯卡尔算法:

首先看一下它的基本思想:先构造一个只含 n 个顶点的子图 SG,然后从权值最小的边开始,若它的添加不使SG 中产生回路,则在 SG 上加上这条边,如此重复,直至加上 n-1 条边为止。一句话,“不构成环的情况下,每次选取最小边” 。它的出发点就是为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能地小。因此我们就从权值最小的边开始构造,前提是不构成环。

那么我们直接从图中找权值最小的边进行组合,首先是BD,然后是BF,BC,CF不行,因为其构成了环,AB可以,EF也可以,ok,这样就得到了最小生成树边的集合TE={BD,BF,BC,AB,EF},是不是比Prim算法简单的多?!

所以该图的最小生成树可以表示为T=({A,B,D,F,C,E},{BD,BF,BC,AB,EF}),当然最好还是可以画出图来,这样会更加直接明了。

关于最小生成树问题,布布扣,bubuko.com

时间: 2024-08-07 04:34:02

关于最小生成树问题的相关文章

最小生成树问题

最小生成树问题 #include <iostream> using namespace std; #define MAX 20 #define INF 32767 int edges[MAX][MAX]; void prim(int v,int arr[MAX][MAX]) { int n=8; int lowcost[MAX]; int min; int closest[MAX],i,j,k; for(i=0;i<n;i++) { lowcost[i]=arr[v][i]; close

杭电1233——还是通畅工程~简单最小生成树问题

这题,典型的最小生成树问题,可以用Kruskal算法来实现,配合着并查集来高效求解. 先将各边按权值进行从小到大排列.遍历一个各边便可求解,时间复杂度为O(|E|log|V|),其中E为边的个数,V为顶点数. 下面是AC代码,代码中有注释: #include <iostream> #include <cstdio> #include <algorithm> using namespace std; class data { public: int from, to, c

数据结构--图(下)--最小生成树问题

最小生成树问题 村村通中,修路,最少的钱就连通起来了.连通图.最少的边, prim算法 思路是:从根节点开始让一棵小树慢慢长大

浅入浅出数据结构(25)——最小生成树问题

上一篇博文我们提到了图的最短路径问题:http://www.cnblogs.com/mm93/p/8434056.html.而最短路径问题可以说是这样的一个问题:路已经修好了,该怎么从这儿走到那儿?但是在和图有关的问题中,还有另一种有趣的问题:修路的成本已经知道了,该怎么修路才能尽可能节约成本,同时将这些地方都连起来? 比如我们知道有这么几个城市,它们互相之间还没有路: 经过实地考察后,发现可以修的路以及各条路的修路成本如下: 但是我们的预算有限,需要在修路时尽可能的省钱(也就是尽量减小所有边的

Agri-Net(prim算法,最小生成树问题)

看图便知道: 来来上代码: #include <cstdio> #include <cstring> #include <iostream> using namespace std; int main() { int n; while(~scanf("%d",&n)) { int tu[n+1][n+1]; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) scanf("%d

最小生成树问题(并查集解决)

        传统的Prim算法或者是Kruskal算法求最小生成树时,要先把图创建出来,就比较麻烦.         如果用并查集来解决,依次选取权值最小的边,判断它们是否在一个并查集内,如果在则舍去,如果不在则加入,简单了很多. 题目描述 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小.请计算最小的公路总长度. 输入

prim解决最小生成树问题

#include <iostream> #include <algorithm> #include <stdio.h> #include <math.h> using namespace std; const int MAXV = 1000;//最大顶点数 const int INF = 1000000000; //n为顶点数 //MAXV为最大顶点数 int n,m; double G[MAXV][MAXV]; double d[MAXV];// 顶点到集

prim算法和kruskal算法--解最小生成树问题

Prim算法原理: 1)以某一个点开始,寻找当前该点可以访问的所有的边:2)在已经寻找的边中发现最小边,这个边必须有一个点还没有访问过,将还没有访问的点加入我们的集合,记录添加的边:3)寻找当前集合可以访问的所有边,重复2的过程,直到没有新的点可以加入:4)此时由所有边构成的树即为最小生成树. Kruskal算法原理: 现在我们假设一个图有m个节点,n条边.首先,我们需要把m个节点看成m个独立的生成树,并且把n条边按照从小到大的数据进行排列.在n条边中,我们依次取出其中的每一条边,如果发现边的两

普里姆算法(Prim)与最小生成树问题

普里姆算法 @anthor:QYX 普里姆算法在找最小生成树时,将顶点分为两类,一类是在查找的过程中已经包含在树中的(假设为 A 类),剩下的是另一类(假设为 B 类). 对于给定的连通网,起始状态全部顶点都归为 B 类.在找最小生成树时,选定任意一个顶点作为起始点,并将之从 B 类移至 A 类:然后找出 B 类中到 A 类中的顶点之间权值最小的顶点,将之从 B 类移至 A 类,如此重复,直到 B 类中没有顶点为止.所走过的顶点和边就是该连通图的最小生成树. 例如,通过普里姆算法查找图 2(a)