C++ Reference

C++ Reference: Graph

minimum_spanning_tree.h
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_GRAPH_MINIMUM_SPANNING_TREE_H_
15 #define OR_TOOLS_GRAPH_MINIMUM_SPANNING_TREE_H_
16 
17 #include <queue>
18 #include <vector>
19 
20 #include "ortools/base/adjustable_priority_queue-inl.h"
21 #include "ortools/base/adjustable_priority_queue.h"
22 #include "ortools/base/integral_types.h"
24 #include "ortools/util/vector_or_function.h"
25 
26 namespace operations_research {
27 
28 // Implementation of Kruskal's mininumum spanning tree algorithm (c.f.
29 // https://en.wikipedia.org/wiki/Kruskal%27s_algorithm).
30 // Returns the index of the arcs appearing in the tree; will return a forest if
31 // the graph is disconnected. Nodes without any arcs will be ignored.
32 // Each arc of the graph is interpreted as an undirected arc.
33 // Complexity of the algorithm is O(E * log(E)) where E is the number of arcs
34 // in the graph. Memory usage is O(E * log(E)).
35 
36 // TODO(user): Add a global Minimum Spanning Tree API automatically switching
37 // between Prim and Kruskal depending on problem size.
38 
39 // Version taking sorted graph arcs. Allows somewhat incremental recomputation
40 // of minimum spanning trees as most of the processing time is spent sorting
41 // arcs.
42 // Usage:
43 // ListGraph<int, int> graph(...);
44 // std::vector<int> sorted_arcs = ...;
45 // std::vector<int> mst = BuildKruskalMinimumSpanningTreeFromSortedArcs(
46 // graph, sorted_arcs);
47 //
48 template <typename Graph>
49 std::vector<typename Graph::ArcIndex>
51  const Graph& graph,
52  const std::vector<typename Graph::ArcIndex>& sorted_arcs) {
53  using ArcIndex = typename Graph::ArcIndex;
54  using NodeIndex = typename Graph::NodeIndex;
55  const int num_arcs = graph.num_arcs();
56  int arc_index = 0;
57  std::vector<ArcIndex> tree_arcs;
58  if (graph.num_nodes() == 0) {
59  return tree_arcs;
60  }
61  const int expected_tree_size = graph.num_nodes() - 1;
62  tree_arcs.reserve(expected_tree_size);
64  components.Init(graph.num_nodes());
65  while (tree_arcs.size() != expected_tree_size && arc_index < num_arcs) {
66  const ArcIndex arc = sorted_arcs[arc_index];
67  const NodeIndex tail_class =
68  components.GetClassRepresentative(graph.Tail(arc));
69  const NodeIndex head_class =
70  components.GetClassRepresentative(graph.Head(arc));
71  if (tail_class != head_class) {
72  components.MergeClasses(tail_class, head_class);
73  tree_arcs.push_back(arc);
74  }
75  ++arc_index;
76  }
77  return tree_arcs;
78 }
79 
80 // Version taking an arc comparator to sort graph arcs.
81 // Usage:
82 // ListGraph<int, int> graph(...);
83 // const auto arc_cost = [&graph](int arc) {
84 // return f(graph.Tail(arc), graph.Head(arc));
85 // };
86 // std::vector<int> mst = BuildKruskalMinimumSpanningTree(
87 // graph,
88 // [&arc_cost](int a, int b) { return arc_cost(a) < arc_cost(b); });
89 //
90 template <typename Graph, typename ArcComparator>
91 std::vector<typename Graph::ArcIndex> BuildKruskalMinimumSpanningTree(
92  const Graph& graph, const ArcComparator& arc_comparator) {
93  using ArcIndex = typename Graph::ArcIndex;
94  std::vector<ArcIndex> sorted_arcs(graph.num_arcs());
95  for (const ArcIndex arc : graph.AllForwardArcs()) {
96  sorted_arcs[arc] = arc;
97  }
98  std::sort(sorted_arcs.begin(), sorted_arcs.end(), arc_comparator);
99  return BuildKruskalMinimumSpanningTreeFromSortedArcs(graph, sorted_arcs);
100 }
101 
102 // Implementation of Prim's mininumum spanning tree algorithm (c.f.
103 // https://en.wikipedia.org/wiki/Prim's_algorithm) on undirected connected
104 // graphs.
105 // Returns the index of the arcs appearing in the tree.
106 // Complexity of the algorithm is O(E * log(V)) where E is the number of arcs
107 // in the graph, V is the number of vertices. Memory usage is O(V) + memory
108 // taken by the graph.
109 // Usage:
110 // ListGraph<int, int> graph(...);
111 // const auto arc_cost = [&graph](int arc) -> int64 {
112 // return f(graph.Tail(arc), graph.Head(arc));
113 // };
114 // std::vector<int> mst = BuildPrimMinimumSpanningTree(graph, arc_cost);
115 //
116 template <typename Graph, typename ArcValue>
117 std::vector<typename Graph::ArcIndex> BuildPrimMinimumSpanningTree(
118  const Graph& graph, const ArcValue& arc_value) {
119  using ArcIndex = typename Graph::ArcIndex;
120  using NodeIndex = typename Graph::NodeIndex;
121  using ArcValueType = decltype(arc_value(0));
122  std::vector<ArcIndex> tree_arcs;
123  if (graph.num_nodes() == 0) {
124  return tree_arcs;
125  }
126  const int expected_tree_size = graph.num_nodes() - 1;
127  tree_arcs.reserve(expected_tree_size);
128  std::vector<ArcIndex> node_neighbor(graph.num_nodes(), Graph::kNilArc);
129  std::vector<bool> node_active(graph.num_nodes(), true);
130 
131  // This struct represents entries in the adjustable priority queue which
132  // maintains active nodes (not added to the tree yet) in decreasing insertion
133  // cost order. AdjustablePriorityQueue requires the existence of the
134  // SetHeapIndex and GetHeapIndex methods.
135  struct Entry {
136  void SetHeapIndex(int index) { heap_index = index; }
137  int GetHeapIndex() const { return heap_index; }
138  bool operator<(const Entry& other) const { return value > other.value; }
139 
140  NodeIndex node;
141  ArcValueType value;
142  int heap_index;
143  };
144 
145  AdjustablePriorityQueue<Entry> pq;
146  std::vector<Entry> entries;
147  std::vector<bool> touched_entry(graph.num_nodes(), false);
148  for (NodeIndex node : graph.AllNodes()) {
149  entries.push_back({node, std::numeric_limits<ArcValueType>::max(), -1});
150  }
151  entries[0].value = 0;
152  pq.Add(&entries[0]);
153  while (!pq.IsEmpty() && tree_arcs.size() != expected_tree_size) {
154  const Entry* best = pq.Top();
155  const NodeIndex node = best->node;
156  pq.Pop();
157  node_active[node] = false;
158  if (node_neighbor[node] != Graph::kNilArc) {
159  tree_arcs.push_back(node_neighbor[node]);
160  }
161  for (const ArcIndex arc : graph.OutgoingArcs(node)) {
162  const NodeIndex neighbor = graph.Head(arc);
163  if (node_active[neighbor]) {
164  const ArcValueType value = arc_value(arc);
165  Entry& entry = entries[neighbor];
166  if (value < entry.value || !touched_entry[neighbor]) {
167  node_neighbor[neighbor] = arc;
168  entry.value = value;
169  touched_entry[neighbor] = true;
170  if (pq.Contains(&entry)) {
171  pq.NoteChangedPriority(&entry);
172  } else {
173  pq.Add(&entry);
174  }
175  }
176  }
177  }
178  }
179  return tree_arcs;
180 }
181 
182 } // namespace operations_research
183 #endif // OR_TOOLS_GRAPH_MINIMUM_SPANNING_TREE_H_
std::vector< typename Graph::ArcIndex > BuildKruskalMinimumSpanningTreeFromSortedArcs(const Graph &graph, const std::vector< typename Graph::ArcIndex > &sorted_arcs)
std::vector< typename Graph::ArcIndex > BuildKruskalMinimumSpanningTree(const Graph &graph, const ArcComparator &arc_comparator)
ListGraph Graph
Definition: graph.h:2354
Definition: christofides.h:33
NodeIndex GetClassRepresentative(NodeIndex node)
Definition: connectivity.h:123
std::vector< typename Graph::ArcIndex > BuildPrimMinimumSpanningTree(const Graph &graph, const ArcValue &arc_value)
void Init(NodeIndex num_nodes)
Definition: connectivity.h:72
int32 ArcIndex
Definition: ebert_graph.h:201
void MergeClasses(NodeIndex node1, NodeIndex node2)
Definition: connectivity.h:138
int32 NodeIndex
Definition: ebert_graph.h:192
Definition: connectivity.h:67