新浪新闻客户端

漫画:什么是最小生成树?

漫画:什么是最小生成树?
2019年07月20日 14:05 新浪网 作者 动漫迷踪

  

漫画:什么是最小生成树?

  作者 | 小灰

  来源 | 程序员小灰

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  ————— 第二天 —————

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  ————————————

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  首先看看第一个例子,有下面这样一个带权图:

  

漫画:什么是最小生成树?

  它的最小生成树是什么样子呢?下图绿色加粗的边可以把所有顶点连接起来,又保证了边的权值之和最小:

  

漫画:什么是最小生成树?

  去掉那些多余的边,该图的最小生成树如下:

  

漫画:什么是最小生成树?

  下面我们再来看一个更加复杂的带权图:

  

漫画:什么是最小生成树?

  同样道理,下图绿色加粗的边可以把所有顶点连接起来,又保证了边的权值之和最小:

  

漫画:什么是最小生成树?

  去掉那些多余的边,该图的最小生成树如下:

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  怎样铺设才能保证成本最低呢?

  城市之间的交通网就像一个连通图,我们并不需要在每两个城市之间都直接进行连接,只需要一个最小生成树,保证所有的城市都有铁路可以触达即可。

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  Prim算法是如何工作的呢?

  这个算法是以图的顶点为基础,从一个初始顶点开始,寻找触达其他顶点权值最小的边,并把该顶点加入到已触达顶点的集合中。当全部顶点都加入到集合时,算法的工作就完成了。Prim算法的本质,是基于

  贪心算法

  

  接下来说一说最小生成树的存储方式。我们最常见的树的存储方式,是链式存储,每一个节点包含若干孩子节点的指针,每一个孩子节点又包含更多孩子节点的指针:

  这样的存储结构很清晰,但是也相对麻烦。为了便于操作,我们的最小生成树用一维数组来表达,数组下标所对应的元素,代表该顶点在最小生成树当中的父亲节点。(根节点没有父亲节点,所以元素值是-1)

  

漫画:什么是最小生成树?

  下面让我们来看一看算法的详细过程:

  1.选择初始顶点,加入到已触达顶点集合。

  

漫画:什么是最小生成树?

  2.从已触达顶点出发,寻找到达新顶点的权值最小的边。显然从0到2的边权值最小,把顶点2加入到已触达顶点集合,Parents当中,下标2对应的父节点是0。

  

漫画:什么是最小生成树?

  3.从已触达顶点出发,寻找到达新顶点的权值最小的边。显然从2到4的边权值最小,把顶点4加入到已触达顶点集合,Parents当中,下标4对应的父节点是2。

  

漫画:什么是最小生成树?

  4.从已触达顶点出发,寻找到达新顶点的权值最小的边。显然从0到1的边权值最小,把顶点1加入到已触达顶点集合,Parents当中,下标1对应的父节点是0。

  

漫画:什么是最小生成树?

  5.从已触达顶点出发,寻找到达新顶点的权值最小的边。显然从1到3的边权值最小,把顶点3加入到已触达顶点集合,Parents当中,下标3对应的父节点是1。

  

漫画:什么是最小生成树?

  这样一来,所有顶点都加入到了已触达顶点集合,而最小生成树就存储在Parents数组当中。

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  final static int INF = Integer.MAX_VALUE;

  public static int prim(int[][] matrix){

  List

  reachedVertexList = new ArrayList

  ;

  //选择顶点0为初始顶点,放入已触达顶点集合中

  reachedVertexList.a

  dd

  (0);

  //创建最小生成树数组,首元素设为-1

  int parents = new int[matrix.length];

  parents[0] = -1;

  //边的权重

  int weight;

  //源顶点下标

  int fromIndex = 0;

  //目标顶点下标

  int toIndex = 0;

  while (reachedVertexList.size

  weight = INF;

  //在已触达的顶点中,寻找到达新顶点的最短边

  for (Integer verte

  xI

  ndex : reachedVertexList) {

  for (int i = 0; i

  if (!reachedVertexList.contains(i)) {

  if (matrix[verte

  xI

  ndex][i]

  fromIndex = verte

  xI

  ndex;

  toIndex = i;

  weight = matrix[verte

  xI

  ndex][i];

  }

  }

  }

  }

  //确定了权值最小的目标顶点,放入已触达顶点集合

  reachedVertexList.a

  dd

  (toIndex);

  //放入最小生成树的数组

  parents[toIndex] = fromIndex;

  }

  return parents;

  }

  public static void main(String[] args) {

  int matrix = new int{

  {0, 4, 3, INF, INF},

  {4, 0, 8, 7, INF},

  {3, 8, 0, INF, 1},

  {INF, 7, INF, 0, 9},

  {INF, INF, 1, 9, 0},

  };

  int parents = prim(matrix);

  System.out.println(Arrays.toString(parents));

  }

  这段代码当中,图的存储方式是邻接矩阵,在main函数中作为测试用例的图和对应的邻接矩阵如下:

  

漫画:什么是最小生成树?

  当然,也可以使用邻接表来实现prim算法,有兴趣的小伙伴可以尝试写一下代码。

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

  

漫画:什么是最小生成树?

特别声明:以上文章内容仅代表作者本人观点,不代表新浪网观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与新浪网联系。
权利保护声明页/Notice to Right Holders

举报邮箱:jubao@vip.sina.com

Copyright © 1996-2024 SINA Corporation

All Rights Reserved 新浪公司 版权所有