zoukankan      html  css  js  c++  java
  • Prim 最小生成树算法

    Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法。和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm)

    Prim 算法的思想很简单,一棵生成树必须连接所有的顶点,而要保持最小权重则每次选择邻接的边时要选择较小权重的边。Prim 算法看起来非常类似于单源最短路径 Dijkstra 算法,从源点出发,寻找当前的最短路径,每次比较当前可达邻接顶点中最小的一个边加入到生成树中。

    例如,下面这张连通的无向图 G,包含 9 个顶点和 14 条边,所以期待的最小生成树应包含 (9 - 1) = 8 条边。

    创建 mstSet 包含到所有顶点的距离,初始为 INF,源点 0 的距离为 0,{0, INF, INF, INF, INF, INF, INF, INF, INF}。

    选择当前最短距离的顶点,即还是顶点 0,将 0 加入 MST,此时邻接顶点为 1 和 7。

    选择当前最小距离的顶点 1,将 1 加入 MST,此时邻接顶点为 2。

    选择 2 和 7 中最小距离的顶点为 7,将 7 加入 MST,此时邻接顶点为 6 和 8。

    选择 2, 6, 8 中最小距离的顶点为 6,将 6 加入 MST,此时邻接顶点为 5。

    重复上面步骤直到遍历完所有顶点为止,会得到如下 MST。

    C# 实现 Prim 算法如下。Prim 算法可以达到 O(ElogV) 的运行时间,如果采用斐波那契堆实现,运行时间可以减少到 O(E + VlogV),如果 V 远小于 E 的话,将是对算法较大的改进。

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 
      5 namespace GraphAlgorithmTesting
      6 {
      7   class Program
      8   {
      9     static void Main(string[] args)
     10     {
     11       Graph g = new Graph(9);
     12       g.AddEdge(0, 1, 4);
     13       g.AddEdge(0, 7, 8);
     14       g.AddEdge(1, 2, 8);
     15       g.AddEdge(1, 7, 11);
     16       g.AddEdge(2, 3, 7);
     17       g.AddEdge(2, 5, 4);
     18       g.AddEdge(3, 4, 9);
     19       g.AddEdge(3, 5, 14);
     20       g.AddEdge(5, 4, 10);
     21       g.AddEdge(6, 5, 2);
     22       g.AddEdge(7, 6, 1);
     23       g.AddEdge(7, 8, 7);
     24       g.AddEdge(8, 2, 2);
     25       g.AddEdge(8, 6, 6);
     26 
     27       // sorry, this is an undirect graph,
     28       // so, you know that this is not a good idea.
     29       List<Edge> edges = g.Edges
     30         .Select(e => new Edge(e.End, e.Begin, e.Weight))
     31         .ToList();
     32       foreach (var edge in edges)
     33       {
     34         g.AddEdge(edge.Begin, edge.End, edge.Weight);
     35       }
     36 
     37       Console.WriteLine();
     38       Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
     39       Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
     40       Console.WriteLine();
     41 
     42       List<Edge> mst = g.Prim();
     43       Console.WriteLine("MST Edges:");
     44       foreach (var edge in mst.OrderBy(e => e.Weight))
     45       {
     46         Console.WriteLine("	{0}", edge);
     47       }
     48 
     49       Console.ReadKey();
     50     }
     51 
     52     class Edge
     53     {
     54       public Edge(int begin, int end, int weight)
     55       {
     56         this.Begin = begin;
     57         this.End = end;
     58         this.Weight = weight;
     59       }
     60 
     61       public int Begin { get; private set; }
     62       public int End { get; private set; }
     63       public int Weight { get; private set; }
     64 
     65       public override string ToString()
     66       {
     67         return string.Format(
     68           "Begin[{0}], End[{1}], Weight[{2}]",
     69           Begin, End, Weight);
     70       }
     71     }
     72 
     73     class Graph
     74     {
     75       private Dictionary<int, List<Edge>> _adjacentEdges
     76         = new Dictionary<int, List<Edge>>();
     77 
     78       public Graph(int vertexCount)
     79       {
     80         this.VertexCount = vertexCount;
     81       }
     82 
     83       public int VertexCount { get; private set; }
     84 
     85       public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } }
     86 
     87       public IEnumerable<Edge> Edges
     88       {
     89         get { return _adjacentEdges.Values.SelectMany(e => e); }
     90       }
     91 
     92       public int EdgeCount { get { return this.Edges.Count(); } }
     93 
     94       public void AddEdge(int begin, int end, int weight)
     95       {
     96         if (!_adjacentEdges.ContainsKey(begin))
     97         {
     98           var edges = new List<Edge>();
     99           _adjacentEdges.Add(begin, edges);
    100         }
    101 
    102         _adjacentEdges[begin].Add(new Edge(begin, end, weight));
    103       }
    104 
    105       public List<Edge> Prim()
    106       {
    107         // Array to store constructed MST
    108         int[] parent = new int[VertexCount];
    109 
    110         // Key values used to pick minimum weight edge in cut
    111         int[] keySet = new int[VertexCount];
    112 
    113         // To represent set of vertices not yet included in MST
    114         bool[] mstSet = new bool[VertexCount];
    115 
    116         // Initialize all keys as INFINITE
    117         for (int i = 0; i < VertexCount; i++)
    118         {
    119           keySet[i] = int.MaxValue;
    120           mstSet[i] = false;
    121         }
    122 
    123         // Always include first 1st vertex in MST.
    124         // Make key 0 so that this vertex is picked as first vertex
    125         keySet[0] = 0;
    126         parent[0] = -1; // First node is always root of MST 
    127 
    128         // The MST will have V vertices
    129         for (int i = 0; i < VertexCount - 1; i++)
    130         {
    131           // Pick thd minimum key vertex from the set of vertices
    132           // not yet included in MST
    133           int u = CalculateMinDistance(keySet, mstSet);
    134 
    135           // Add the picked vertex to the MST Set
    136           mstSet[u] = true;
    137 
    138           // Update key value and parent index of the adjacent vertices of
    139           // the picked vertex. Consider only those vertices which are not yet
    140           // included in MST
    141           for (int v = 0; v < VertexCount; v++)
    142           {
    143             // graph[u, v] is non zero only for adjacent vertices of m
    144             // mstSet[v] is false for vertices not yet included in MST
    145             // Update the key only if graph[u, v] is smaller than key[v]
    146             if (!mstSet[v]
    147               && _adjacentEdges.ContainsKey(u)
    148               && _adjacentEdges[u].Exists(e => e.End == v))
    149             {
    150               int d = _adjacentEdges[u].Single(e => e.End == v).Weight;
    151               if (d < keySet[v])
    152               {
    153                 keySet[v] = d;
    154                 parent[v] = u;
    155               }
    156             }
    157           }
    158         }
    159 
    160         // get all MST edges
    161         List<Edge> mst = new List<Edge>();
    162         for (int i = 1; i < VertexCount; i++)
    163           mst.Add(_adjacentEdges[parent[i]].Single(e => e.End == i));
    164 
    165         return mst;
    166       }
    167 
    168       private int CalculateMinDistance(int[] keySet, bool[] mstSet)
    169       {
    170         int minDistance = int.MaxValue;
    171         int minDistanceIndex = -1;
    172 
    173         for (int v = 0; v < VertexCount; v++)
    174         {
    175           if (!mstSet[v] && keySet[v] <= minDistance)
    176           {
    177             minDistance = keySet[v];
    178             minDistanceIndex = v;
    179           }
    180         }
    181 
    182         return minDistanceIndex;
    183       }
    184     }
    185   }
    186 }

    输出结果如下:

    参考资料

    本篇文章《Prim 最小生成树算法》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。

  • 相关阅读:
    CSS3相关编码规范
    WEB开发中常见的漏洞
    Python常用端口扫描
    33、Django实战第33天:我的消息
    32、Django实战第32天:我的收藏
    31、Django实战第31天:我的课程
    30、Django实战第30天:修改邮箱和用户信息
    29、Django实战第29天:修改密码和头像
    28、Django实战第28天:个人信息展示
    27、Django实战第27天:全局搜索功能开发
  • 原文地址:https://www.cnblogs.com/gaochundong/p/prim_minimum_spanning_tree.html
Copyright © 2011-2022 走看看