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

快来打我* 2023-07-17 11:28 102阅读 0赞

format_png

format_png 1

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

format_png 2

format_png 3

format_png 4

format_png 5

format_png 6

format_png 7

format_png 8

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

format_png 9

format_png 10

format_png 11

format_png 12

format_png 13

format_png 14

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

format_png 15

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

format_png 16

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

format_png 17

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

format_png 18

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

format_png 19

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

format_png 20

format_png 21

format_png 22

format_png 23

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

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

format_png 24

format_png 25

format_png 26

Prim算法是如何工作的呢?

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

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

format_png 20

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

format_png 27

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

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

format_png 28

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

format_png 29

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

format_png 30

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

format_png 31

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

format_png 32

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

format_png 33

format_png 34

  1. final static int INF = Integer.MAX_VALUE;
  2. public static int[] prim(int[][] matrix){
  3. List<Integer> reachedVertexList = new ArrayList<Integer>();
  4. //选择顶点0为初始顶点,放入已触达顶点集合中
  5. reachedVertexList.add(0);
  6. //创建最小生成树数组,首元素设为-1
  7. int[] parents = new int[matrix.length];
  8. parents[0] = -1;
  9. //边的权重
  10. int weight;
  11. //源顶点下标
  12. int fromIndex = 0;
  13. //目标顶点下标
  14. int toIndex = 0;
  15. while (reachedVertexList.size() < matrix.length) {
  16. weight = INF;
  17. //在已触达的顶点中,寻找到达新顶点的最短边
  18. for (Integer vertexIndex : reachedVertexList) {
  19. for (int i = 0; i < matrix.length; i++) {
  20. if (!reachedVertexList.contains(i)) {
  21. if (matrix[vertexIndex][i] < weight) {
  22. fromIndex = vertexIndex;
  23. toIndex = i;
  24. weight = matrix[vertexIndex][i];
  25. }
  26. }
  27. }
  28. }
  29. //确定了权值最小的目标顶点,放入已触达顶点集合
  30. reachedVertexList.add(toIndex);
  31. //放入最小生成树的数组
  32. parents[toIndex] = fromIndex;
  33. }
  34. return parents;
  35. }
  36. public static void main(String[] args) {
  37. int[][] matrix = new int[][]{
  38. {0, 4, 3, INF, INF},
  39. {4, 0, 8, 7, INF},
  40. {3, 8, 0, INF, 1},
  41. {INF, 7, INF, 0, 9},
  42. {INF, INF, 1, 9, 0},
  43. };
  44. int[] parents = prim(matrix);
  45. System.out.println(Arrays.toString(parents));
  46. }

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

format_png 35

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

format_png 36

format_png 37

—————END—————

发表评论

表情:
评论列表 (有 0 条评论,102人围观)

还没有评论,来说两句吧...

相关阅读

    相关 漫画什么B+

    在上一篇漫画中,我们介绍了B-树的原理和应用,没看过的小伙伴们可以点击下面的链接:   [漫画:什么是B-树?][B-]   这一次我们来介绍B+树。     —

    相关 生成算法

    在上一篇文章中,我们看了一下图的遍历算法,主要是对图的深度优先遍历和图的广度优先遍历算法思想的介绍。接下来让我们来看一下图的最小声成树算法。 首先,我们要知道,图的最小生成树

    相关 论-生成

    给定一个无向图,如果它的某一个子图中任意俩个顶点都互相联通并且是一棵树,那么这棵树就是生成树。如果边上还有权值,边权和最小的称为最小生成树。 算法1:Prim算法