最小生成树

来源:互联网 发布:网络售后服务包括 编辑:程序博客网 时间:2024/06/05 00:15

一颗带权无向图的生成树的代价是该生成树中所有边的代价之和,最小代价生成树就是一颗代价最小的生成树,构建无向图的最小生成树就是采用贪心算法,不过对于最小生成树问题,需满足以下约束条件:

  • 只能使用图中的边
  • 只能使用恰好n-1条边
  • 不能使用产生环路的边
    Kruskal算法通过每次向当前最小代价生成树T中加入一条边的方法构成最终的最小生成树T,算法按照边的代价非递减的顺序选取,并加入T中,如果所选取的边与T中的边不形成环路,则这条边加入到T中,由于图G是连通的,且具有n个顶点,所以最终恰好选取n-1条边加入到T中。
    如图所示:
    这里写图片描述
边 权值 结果 … … 初始化 (0,5) 10 加入树 (2,3) 12 加入 (1,6) 14 加入 (1,2) 16 加入 (3,6) 18 丢弃 (3,4) 22 加入 (4,6) 24 丢弃 (4,5) 25 加入 (0,1) 28 不再考虑

为了实现Kruskal算法,必须找出最小代价的边并将其从E中删除,如果把E中的边按权值进行排序,保存为一个顺序表,就可以有效的完成上述两个操作,但实际上,只要能够快速地找到下一条边最小代价的边,就没有要对E中的边进行排序,显然最小堆非常适合这个任务,因为最小堆可以在O(loge)时间内找出并删除下一条最小权值的边,而构造最小堆本身的时间复杂性为O(e).
伪代码实现:

//最小生成树算法void create minTree(){   T={};//最小生成树的集合   //T的边数需小于n-1,却无向图的边不能为空   while(T.edgesCount<n-1&&E.edgesCount>0)   {      minHeap(v,w,E);//从无向图E集合选择最小代价的边      delete(v,w,E);//删除该边      //如果新加入边不构成环,则加入,否则丢弃      if(!isCycle(v,w,T))      {         add(v,w,T)      }      else      {         discard(v,w)      }   }   //检查最小生成树的边数是否满足约束条件   if(T.egdescount!=n-1)   {      printf("No spanning tree\n");   }}
0 0