最小生成树问题的算法笔记

本文介绍了最小生成树问题,包括其定义、输入输出,详细解析了普里姆算法和克鲁斯卡尔算法的原理,并通过实例展示了这两种算法的加点法和加边法。此外,还提供了Java和C语言的代码实现,以及算法应用在通信网络优化中的场景。
摘要由CSDN通过智能技术生成

最小生成树问题


前提

在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得联通所有结点的的 w(T) 最小,则此 T 为 G 的最小生成树。
最小生成树其实是最小权重生成树的简称。
先回忆回忆什么是树、什么是图、什么是最小生成树。

1 描述最小生成树问题算法的输入、输出

1.1 最小生成树问题算法的输入:由实际生活中的点和边构成的图,如基电站和电缆线路、景点和公路等抽象化出来的图;

1.2 最小生成树问题算法的输出:由输入的图经过Prim算法或者Kruskal 算法等处理最终得到一个各条边权值之和最小的树,而得到的这棵树叫做最小生成树,该生成树往往是修公路的费用最小化的修路方式、修电站的通信的电线的费用最小化的修造方式。

1.3 最小生成树要解决的两个问题:

(1)尽可能选取权值小的边,但不能构成回路;

(2)选取n-1条恰当的边以连接网的n个顶点。

1.4 构成网的一棵最小生成树,即:在e条带权的边中选取n-1条边(不构成回路),使“权值之和”为最小。


2 普里姆算法(Prim)

2.1 本质:加点法

2.2 基本思想:

取图中任意一个顶点V作为生成树的根,之后往生成树上添加新的顶点W。在添加的顶点W和已经在生成树上的顶点V之间必定存在一条边,该边的权值在所有连通项点V和W之间的边中取值为最小。之后继续往生成树上添加顶点,直至生成树上含有n个顶点为止。

2.3 具体做法:

在生成树的构造过程中,让连通图中n个顶点分属两个集合:已经加入到生成树上的顶点集合U和(原连通图上)还没加入到生成树上的顶点集合V-U;每次在V-U集合里选中一个和生成树上某一个顶点连线中权值最小的,将此顶点加入到生成树里。

2.4 实例:

(1)如下带权无向连通图1:

在这里插入图片描述

图1

(2)从顶点a开始加点:

说明:可能考虑的边的权值,这一列的数据,标志为红色是指这权值为X1的边的两个顶点为U集合;标志为蓝色是指这权值为X2的边再次被遇到,但这边不能在本次最小生成树;为空,则表示Prim算法结束。
在这里插入图片描述

(3)最终得到最小生成树,如下图中的用红色边连通的顶点所构成的树:
在这里插入图片描述
(4)主要代码(用java实现):

public static void onChangeVertex(Vertex vertex) {
   
  visitedVertexs.add(vertex); //添加初始节点,作为默认的开始节点
  leftedVertexs.remove(vertex);
}

public static Vertex findOneVertex(Graph g) {
   
  int minValue = Integer.MAX_VALUE;
  Vertex findVertex = new Vertex();
  Edge findEdge = new Edge();

  for(int i=0;i<visitedVertexs.size();i++) {
   
    for(int j=0;j<leftedVertexs.size();j++) {
   
      Vertex v1 = visitedVertexs.get(i);
      Vertex v2 = leftedVertexs.get(j); //获取两个顶点的名称

      for(int k=0;k<g.edge.length;k++) {
   
        String startName = g.edge[k].startVertex.vName;
        String endName = g.edge[k].endVertex.vName;

        if((v1.vName.equals(startName) && v2.vName.equals(endName)) ||(v1.vName.equals(endName) && v2.vName.equals(startName))){
   
          if(g.edge[k].weight < minValue) {
   
            findEdge = g.edge[k];
            minValue = g.edge[k].weight;
            if(leftedVertexs.contains(v1)){
    //会调用对象的equals方法比较对象,需重写equals方法
              findVertex = v1;
            }else if(leftedVertexs.contains(v2)){
   
              findVertex = v2;
            }
          }
        }
      }
    }
  }
  g.minWeight+= minValue;
  searchEdges.add(findEdge);

  return findVertex;
}

public static void prim(Graph g) {
   
  while(leftedVertexs.size()>0){
    //直到剩余节点集为空时结束循环
    Vertex findVertex = findOneVertex(g);
    onChangeVertex(findVertex);
  }
  System.out.print("\n最短路径包含的边: ");
  for(int i=0;i<searchEdges.size();i++) {
   
    System.out.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值