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 和 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("\t{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 }输出结果如下:
参考资料
Connectivity in a directed graph
Strongly Connected Components
Tarjan's Algorithm to find Strongly Connected Components
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章







