TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
lowest_common_ancestor.cpp
Go to the documentation of this file.
1
38#include <cassert>
39#include <iostream>
40#include <queue>
41#include <utility>
42#include <vector>
43
48namespace graph {
53class Graph {
54 public:
62 Graph(size_t N, const std::vector<std::pair<int, int> > &undirected_edges) {
63 neighbors.resize(N);
64 for (auto &edge : undirected_edges) {
65 neighbors[edge.first].push_back(edge.second);
66 neighbors[edge.second].push_back(edge.first);
67 }
68 }
69
74 int number_of_vertices() const { return neighbors.size(); }
75
77 std::vector<std::vector<int> > neighbors;
78};
79
84class RootedTree : public Graph {
85 public:
93 RootedTree(const std::vector<std::pair<int, int> > &undirected_edges,
94 int root_)
95 : Graph(undirected_edges.size() + 1, undirected_edges), root(root_) {
97 }
98
104 std::vector<int> parent;
106 std::vector<int> level;
108 int root;
109
110 protected:
118 // Initialize the vector with -1 which indicates the vertex
119 // wasn't yet visited.
120 parent = std::vector<int>(number_of_vertices(), -1);
121 level = std::vector<int>(number_of_vertices());
122 parent[root] = root;
123 level[root] = 0;
124 std::queue<int> queue_of_vertices;
125 queue_of_vertices.push(root);
126 while (!queue_of_vertices.empty()) {
127 int vertex = queue_of_vertices.front();
128 queue_of_vertices.pop();
129 for (int neighbor : neighbors[vertex]) {
130 // As long as the vertex was not yet visited.
131 if (parent[neighbor] == -1) {
132 parent[neighbor] = vertex;
133 level[neighbor] = level[vertex] + 1;
134 queue_of_vertices.push(neighbor);
135 }
136 }
137 }
138 }
139};
140
146 public:
151 explicit LowestCommonAncestor(const RootedTree &tree_) : tree(tree_) {
152 populate_up();
153 }
154
164 int lowest_common_ancestor(int u, int v) const {
165 // Ensure u is the deeper (higher level) of the two vertices
166 if (tree.level[v] > tree.level[u]) {
167 std::swap(u, v);
168 }
169
170 // "Lift" u to the same level as v.
171 int level_diff = tree.level[u] - tree.level[v];
172 for (int i = 0; (1 << i) <= level_diff; ++i) {
173 if (level_diff & (1 << i)) {
174 u = up[u][i];
175 }
176 }
177 assert(tree.level[u] == tree.level[v]);
178
179 if (u == v) {
180 return u;
181 }
182
183 // "Lift" u and v to their 2^i th ancestor if they are different
184 for (int i = static_cast<int>(up[u].size()) - 1; i >= 0; --i) {
185 if (up[u][i] != up[v][i]) {
186 u = up[u][i];
187 v = up[v][i];
188 }
189 }
190
191 // As we regressed u an v such that they cannot further be lifted so
192 // that their ancestor would be different, the only logical
193 // consequence is that their parent is the sought answer.
194 assert(up[u][0] == up[v][0]);
195 return up[u][0];
196 }
197
198 /* \brief reference to the rooted tree this structure allows to query */
199 const RootedTree &tree;
206 std::vector<std::vector<int> > up;
207
208 protected:
212 void populate_up() {
213 up.resize(tree.number_of_vertices());
214 for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) {
215 up[vertex].push_back(tree.parent[vertex]);
216 }
217 for (int level = 0; (1 << level) < tree.number_of_vertices(); ++level) {
218 for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) {
219 // up[vertex][level + 1] = 2^(level + 1) th ancestor of vertex =
220 // = 2^level th ancestor of 2^level th ancestor of vertex =
221 // = 2^level th ancestor of up[vertex][level]
222 up[vertex].push_back(up[up[vertex][level]][level]);
223 }
224 }
225 }
226};
227
228} // namespace graph
229
234static void tests() {
244 std::vector<std::pair<int, int> > edges = {
245 {7, 1}, {1, 5}, {1, 3}, {3, 6}, {6, 2}, {2, 9}, {6, 8}, {4, 3}, {0, 4}};
246 graph::RootedTree t(edges, 3);
248 assert(lca.lowest_common_ancestor(7, 4) == 3);
249 assert(lca.lowest_common_ancestor(9, 6) == 6);
250 assert(lca.lowest_common_ancestor(0, 0) == 0);
251 assert(lca.lowest_common_ancestor(8, 2) == 6);
252}
253
255int main() {
256 tests();
257 return 0;
258}
std::vector< std::vector< int > > neighbors
for each vertex it stores a list indicies of its neighbors
Graph(size_t N, const std::vector< std::pair< int, int > > &undirected_edges)
Populate the adjacency list for each vertex in the graph. Assumes that evey edge is a pair of valid v...
int number_of_vertices() const
std::vector< std::vector< int > > up
for every vertex stores a list of its ancestors by powers of two For each vertex, the first element o...
int lowest_common_ancestor(int u, int v) const
Query the structure to find the lowest common ancestor. Assumes that the provided numbers are valid i...
LowestCommonAncestor(const RootedTree &tree_)
Stores the tree and precomputs "up lifts".
std::vector< int > level
Stores the distance from the root.
std::vector< int > parent
Stores parent of every vertex and for root its own index. The root is technically not its own parent,...
RootedTree(const std::vector< std::pair< int, int > > &undirected_edges, int root_)
Constructs the tree by calculating parent for every vertex. Assumes a valid description of a tree is ...
int root
Index of the root vertex.
void populate_parents()
Calculate the parents for all the vertices in the tree. Implements the breadth first search algorithm...
static void tests()
Graph Algorithms.