From f4c187b9aeb8b379341561e87fef100322582a78 Mon Sep 17 00:00:00 2001 From: David Leal Date: Sun, 9 Aug 2020 14:00:54 -0500 Subject: [PATCH 1/9] [fix/docs]: Improve backtracking/n_queens.cpp --- backtracking/n_queens.cpp | 156 ++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 48 deletions(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index 8aab5df7b..6da8d8679 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -1,63 +1,123 @@ +/** + * @file n_queens.cpp + * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) + * puzzle + * + * @details + * The **eight queens puzzle** is the problem of placing eight chess queens on + * an 8×8 chessboard so that no two queens threaten each other; thus, a solution + * requires that no two queens share the same row, column, or diagonal. The + * eight queens puzzle is an example of the more general **n queens problem** of + * placing n non-attacking queens on an n×n chessboard, for which solutions + * exist for all natural numbers n with the exception of n = 2 and n = 3. + * + * @author Unknown author + * @author [David Leal](https://github.com/Panquesito7) + * + */ #include -#define N 4 -using namespace std; +#include -void printSolution(int board[N][N]) { - cout << "\n"; - for (int i = 0; i < N; i++) { - for (int j = 0; j < N; j++) cout << "" << board[i][j]; - cout << "\n"; +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * Utility function to print matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + */ +template +void printSolution(const std::array, n> &board) { + std::cout << "\n"; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + std::cout << "" << board[i][j]; } + std::cout << "\n"; + } } -bool isSafe(int board[N][N], int row, int col) { - int i, j; +/** + * Check if a queen can be placed on matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param row current index in rows + * @param col current index in columns + * @returns `true` if queen can be placed on matrix + * @returns `false` if queen can't be placed on matrix + */ +template +bool isSafe(const std::array, n> &board, const int &row, + const int &col) { + int i = 0, j = 0; - /* Check this row on left side */ - for (i = 0; i < col; i++) - if (board[row][i]) - return false; + // Check this row on left side + for (i = 0; i < col; i++) { + if (board[row][i]) { + return false; + } + } - /* Check upper diagonal on left side */ - for (i = row, j = col; i >= 0 && j >= 0; i--, j--) - if (board[i][j]) - return false; - - /* Check lower diagonal on left side */ - for (i = row, j = col; j >= 0 && i < N; i++, j--) - if (board[i][j]) - return false; - - return true; + // Check upper diagonal on left side + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { + if (board[i][j]) { + return false; + } + } + // Check lower diagonal on left side + for (i = row, j = col; j >= 0 && i < n; i++, j--) { + if (board[i][j]) { + return false; + } + } + return true; } -void solveNQ(int board[N][N], int col) { - if (col >= N) { - printSolution(board); - return; - } - - /* Consider this column and try placing - this queen in all rows one by one */ - for (int i = 0; i < N; i++) { - /* Check if queen can be placed on - board[i][col] */ - if (isSafe(board, i, col)) { - /* Place this queen in board[i][col] */ - // cout<<"\n"< +void solveNQ(std::array, n> board, const int &col) { + if (col >= n) { + printSolution(board); + return; + } + + // Consider this column and try placing + // this queen in all rows one by one + for (int i = 0; i < n; i++) { + // Check if queen can be placed + // on board[i][col] + if (isSafe(board, i, col)) { + // Place this queen in matrix + board[i][col] = 1; + + // Recur to place rest of the queens + solveNQ(board, col + 1); + + board[i][col] = 0; // backtrack } + } } +} // namespace backtracking +/** + * Main function + */ int main() { - int board[N][N] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; + const int n = 4; + std::array, n> board = { + std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}) + }; - solveNQ(board, 0); - return 0; + backtracking::solveNQ(board, 0); + return 0; } From de5f695afadbe58d0f0015fc9030b9921f55abf1 Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 10 Aug 2020 12:37:06 -0500 Subject: [PATCH 2/9] fix: Add spaces between numbers --- backtracking/n_queens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index 6da8d8679..d879795ee 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -33,7 +33,7 @@ void printSolution(const std::array, n> &board) { std::cout << "\n"; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - std::cout << "" << board[i][j]; + std::cout << "" << board[i][j] << " "; } std::cout << "\n"; } From 358f56f9bea33093aa767631f23a90b63098b052 Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 10 Aug 2020 12:37:51 -0500 Subject: [PATCH 3/9] docs: Minor correction --- backtracking/n_queens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index d879795ee..c864fff6a 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -97,7 +97,7 @@ void solveNQ(std::array, n> board, const int &col) { // Place this queen in matrix board[i][col] = 1; - // Recur to place rest of the queens + // Recursive to place rest of the queens solveNQ(board, col + 1); board[i][col] = 0; // backtrack From b7621157cb978c5b5e3761bddf6f8ffbc6269216 Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 10 Aug 2020 18:37:51 -0500 Subject: [PATCH 4/9] fix: Add namespace member: n_queens --- backtracking/n_queens.cpp | 156 ++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index c864fff6a..7ba7cf52e 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -23,87 +23,93 @@ * @brief Backtracking algorithms */ namespace backtracking { -/** - * Utility function to print matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - */ -template -void printSolution(const std::array, n> &board) { - std::cout << "\n"; - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - std::cout << "" << board[i][j] << " "; + /** + * @namespace n_queens + * @brief Functions for [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle. + */ + namespace n_queens { + /** + * Utility function to print matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + */ + template + void printSolution(const std::array, n> &board) { + std::cout << "\n"; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + std::cout << "" << board[i][j] << " "; + } + std::cout << "\n"; + } } - std::cout << "\n"; - } -} -/** - * Check if a queen can be placed on matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param row current index in rows - * @param col current index in columns - * @returns `true` if queen can be placed on matrix - * @returns `false` if queen can't be placed on matrix - */ -template -bool isSafe(const std::array, n> &board, const int &row, - const int &col) { - int i = 0, j = 0; + /** + * Check if a queen can be placed on matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param row current index in rows + * @param col current index in columns + * @returns `true` if queen can be placed on matrix + * @returns `false` if queen can't be placed on matrix + */ + template + bool isSafe(const std::array, n> &board, const int &row, + const int &col) { + int i = 0, j = 0; - // Check this row on left side - for (i = 0; i < col; i++) { - if (board[row][i]) { - return false; + // Check this row on left side + for (i = 0; i < col; i++) { + if (board[row][i]) { + return false; + } + } + + // Check upper diagonal on left side + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { + if (board[i][j]) { + return false; + } + } + // Check lower diagonal on left side + for (i = row, j = col; j >= 0 && i < n; i++, j--) { + if (board[i][j]) { + return false; + } + } + return true; } - } - // Check upper diagonal on left side - for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { - if (board[i][j]) { - return false; + /** + * Solve n queens problem + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param col current index in columns + */ + template + void solveNQ(std::array, n> board, const int &col) { + if (col >= n) { + printSolution(board); + return; + } + + // Consider this column and try placing + // this queen in all rows one by one + for (int i = 0; i < n; i++) { + // Check if queen can be placed + // on board[i][col] + if (isSafe(board, i, col)) { + // Place this queen in matrix + board[i][col] = 1; + + // Recursive to place rest of the queens + solveNQ(board, col + 1); + + board[i][col] = 0; // backtrack + } + } } - } - // Check lower diagonal on left side - for (i = row, j = col; j >= 0 && i < n; i++, j--) { - if (board[i][j]) { - return false; - } - } - return true; -} - -/** - * Solve n queens problem - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param col current index in columns - */ -template -void solveNQ(std::array, n> board, const int &col) { - if (col >= n) { - printSolution(board); - return; - } - - // Consider this column and try placing - // this queen in all rows one by one - for (int i = 0; i < n; i++) { - // Check if queen can be placed - // on board[i][col] - if (isSafe(board, i, col)) { - // Place this queen in matrix - board[i][col] = 1; - - // Recursive to place rest of the queens - solveNQ(board, col + 1); - - board[i][col] = 0; // backtrack - } - } -} + } // namespace n_queens } // namespace backtracking /** From d2c3a3f0d0929399a6d58ea919ce6f856bcac5bd Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 10 Aug 2020 18:39:54 -0500 Subject: [PATCH 5/9] fix: lint warnings --- backtracking/n_queens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index 7ba7cf52e..cefc01451 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -124,6 +124,6 @@ int main() { std::array({0, 0, 0, 0}) }; - backtracking::solveNQ(board, 0); + backtracking::n_queens::solveNQ(board, 0); return 0; } From 8454057249a29aa4e2d7cf795e22a6e551009043 Mon Sep 17 00:00:00 2001 From: David Leal Date: Thu, 13 Aug 2020 17:03:56 -0500 Subject: [PATCH 6/9] docs: Remove file name --- backtracking/n_queens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index cefc01451..89d907750 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -1,5 +1,5 @@ /** - * @file n_queens.cpp + * @file * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) * puzzle * From 6794515dc1c68735f63e9b2f789f37e81d3f305e Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Thu, 13 Aug 2020 18:15:48 -0400 Subject: [PATCH 7/9] [enhancement] update openmp version & doxygen path fix (#1021) * exclude 'build' directory from doxygen * bump openmp version to 3.0 OpenMP >= v3.0 supports signed and unsigned for loop variables --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d0ed28c5..57104aa9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ endif(MSVC) option(USE_OPENMP "flag to use OpenMP for multithreading" ON) if(USE_OPENMP) - find_package(OpenMP) + find_package(OpenMP 3.0 COMPONENTS CXX) if (OpenMP_CXX_FOUND) message(STATUS "Building with OpenMP Multithreading.") else() @@ -57,6 +57,7 @@ if(DOXYGEN_FOUND) set(DOXYGEN_STRIP_CODE_COMMENTS NO) set(DOXYGEN_EXT_LINKS_IN_WINDOW YES) set(DOXYGEN_BUILTIN_STL_SUPPORT YES) + set(DOXYGEN_EXCLUDE_PATTERNS */build/*) set(DOXYGEN_ENABLE_PREPROCESSING YES) set(DOXYGEN_CLANG_ASSISTED_PARSING YES) set(DOXYGEN_FILE_PATTERNS *.cpp *.h *.hpp *.md) From def8f4937e5c878cbf7ea9cc29d219426514a5ac Mon Sep 17 00:00:00 2001 From: Filip Hlasek Date: Fri, 14 Aug 2020 09:35:11 -0700 Subject: [PATCH 8/9] Refactor lowest comomon ancestor. (#980) * Refactor lowest comomon ancestor. * Fix linter warnings. * Address comments and linter warnings. * Added Kaprekar number implementation * updating DIRECTORY.md * Added Collatz Conjecture implementation * updating DIRECTORY.md * Added Ugly Numbers implementation * updating DIRECTORY.md * Add lowest common ancestor to the graph namespace. * updating DIRECTORY.md * static tests function * Revert ugly number kaprekar and collatz. Co-authored-by: Deepak Vijay Agrawal <64848982+DebugAgrawal@users.noreply.github.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 2 +- graph/lca.cpp | 99 ------------ graph/lowest_common_ancestor.cpp | 259 +++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 100 deletions(-) delete mode 100644 graph/lca.cpp create mode 100644 graph/lowest_common_ancestor.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 82787cad4..76fa1154d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -84,7 +84,7 @@ * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) * [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kruskal.cpp) - * [Lca](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lca.cpp) + * [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lowest_common_ancestor.cpp) * [Max Flow With Ford Fulkerson And Edmond Karp Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp) * [Prim](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/prim.cpp) * [Topological Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/topological_sort.cpp) diff --git a/graph/lca.cpp b/graph/lca.cpp deleted file mode 100644 index c05cf7b9b..000000000 --- a/graph/lca.cpp +++ /dev/null @@ -1,99 +0,0 @@ -//#include -#include - -using namespace std; -// Find the lowest common ancestor using binary lifting in O(nlogn) -// Zero based indexing -// Resource : https://cp-algorithms.com/graph/lca_binary_lifting.html -const int N = 1005; -const int LG = log2(N) + 1; -struct lca { - int n; - vector adj[N]; // Graph - int up[LG][N]; // build this table - int level[N]; // get the levels of all of them - - lca(int n_) : n(n_) { - memset(up, -1, sizeof(up)); - memset(level, 0, sizeof(level)); - for (int i = 0; i < n - 1; ++i) { - int a, b; - cin >> a >> b; - a--; - b--; - adj[a].push_back(b); - adj[b].push_back(a); - } - level[0] = 0; - dfs(0, -1); - build(); - } - void verify() { - for (int i = 0; i < n; ++i) { - cout << i << " : level: " << level[i] << endl; - } - cout << endl; - for (int i = 0; i < LG; ++i) { - cout << "Power:" << i << ": "; - for (int j = 0; j < n; ++j) { - cout << up[i][j] << " "; - } - cout << endl; - } - } - - void build() { - for (int i = 1; i < LG; ++i) { - for (int j = 0; j < n; ++j) { - if (up[i - 1][j] != -1) { - up[i][j] = up[i - 1][up[i - 1][j]]; - } - } - } - } - - void dfs(int node, int par) { - up[0][node] = par; - for (auto i : adj[node]) { - if (i != par) { - level[i] = level[node] + 1; - dfs(i, node); - } - } - } - int query(int u, int v) { - u--; - v--; - if (level[v] > level[u]) { - swap(u, v); - } - // u is at the bottom. - int dist = level[u] - level[v]; - // Go up this much distance - for (int i = LG - 1; i >= 0; --i) { - if (dist & (1 << i)) { - u = up[i][u]; - } - } - if (u == v) { - return u; - } - assert(level[u] == level[v]); - for (int i = LG - 1; i >= 0; --i) { - if (up[i][u] != up[i][v]) { - u = up[i][u]; - v = up[i][v]; - } - } - assert(up[0][u] == up[0][v]); - return up[0][u]; - } -}; - -int main() { - int n; // number of nodes in the tree. - lca l(n); // will take the input in the format given - // n-1 edges of the form - // a b - // Use verify function to see. -} diff --git a/graph/lowest_common_ancestor.cpp b/graph/lowest_common_ancestor.cpp new file mode 100644 index 000000000..497d83187 --- /dev/null +++ b/graph/lowest_common_ancestor.cpp @@ -0,0 +1,259 @@ +/** + * + * \file + * + * \brief Data structure for finding the lowest common ancestor + * of two vertices in a rooted tree using binary lifting. + * + * \details + * Algorithm: https://cp-algorithms.com/graph/lca_binary_lifting.html + * + * Complexity: + * - Precomputation: \f$O(N \log N)\f$ where \f$N\f$ is the number of vertices in the tree + * - Query: \f$O(\log N)\f$ + * - Space: \f$O(N \log N)\f$ + * + * Example: + *
Tree: + *
+ *             _  3  _
+ *          /     |     \
+ *        1       6       4
+ *      / |     /   \       \
+ *    7   5   2       8       0
+ *            |
+ *            9
+ * 
+ * + *
lowest_common_ancestor(7, 4) = 3 + *
lowest_common_ancestor(9, 6) = 6 + *
lowest_common_ancestor(0, 0) = 0 + *
lowest_common_ancestor(8, 2) = 6 + * + * The query is symmetrical, therefore + * lowest_common_ancestor(x, y) = lowest_common_ancestor(y, x) + */ + +#include +#include +#include +#include +#include + +/** + * \namespace graph + * \brief Graph algorithms + */ +namespace graph { +/** + * Class for representing a graph as an adjacency list. + * Its vertices are indexed 0, 1, ..., N - 1. + */ +class Graph { + public: + /** + * \brief Populate the adjacency list for each vertex in the graph. + * Assumes that evey edge is a pair of valid vertex indices. + * + * @param N number of vertices in the graph + * @param undirected_edges list of graph's undirected edges + */ + Graph(size_t N, const std::vector< std::pair > &undirected_edges) { + neighbors.resize(N); + for (auto &edge : undirected_edges) { + neighbors[edge.first].push_back(edge.second); + neighbors[edge.second].push_back(edge.first); + } + } + + /** + * Function to get the number of vertices in the graph + * @return the number of vertices in the graph. + */ + int number_of_vertices() const { + return neighbors.size(); + } + + /** \brief for each vertex it stores a list indicies of its neighbors */ + std::vector< std::vector > neighbors; +}; + +/** + * Representation of a rooted tree. For every vertex its parent is precalculated. + */ +class RootedTree : public Graph { + public: + /** + * \brief Constructs the tree by calculating parent for every vertex. + * Assumes a valid description of a tree is provided. + * + * @param undirected_edges list of graph's undirected edges + * @param root_ index of the root vertex + */ + RootedTree(const std::vector< std::pair > &undirected_edges, int root_) + : Graph(undirected_edges.size() + 1, undirected_edges), root(root_) { + populate_parents(); + } + + /** + * \brief Stores parent of every vertex and for root its own index. + * The root is technically not its own parent, but it's very practical + * for the lowest common ancestor algorithm. + */ + std::vector parent; + /** \brief Stores the distance from the root. */ + std::vector level; + /** \brief Index of the root vertex. */ + int root; + + protected: + /** + * \brief Calculate the parents for all the vertices in the tree. + * Implements the breadth first search algorithm starting from the root + * vertex searching the entire tree and labeling parents for all vertices. + * @returns none + */ + void populate_parents() { + // Initialize the vector with -1 which indicates the vertex + // wasn't yet visited. + parent = std::vector(number_of_vertices(), -1); + level = std::vector(number_of_vertices()); + parent[root] = root; + level[root] = 0; + std::queue queue_of_vertices; + queue_of_vertices.push(root); + while (!queue_of_vertices.empty()) { + int vertex = queue_of_vertices.front(); + queue_of_vertices.pop(); + for (int neighbor : neighbors[vertex]) { + // As long as the vertex was not yet visited. + if (parent[neighbor] == -1) { + parent[neighbor] = vertex; + level[neighbor] = level[vertex] + 1; + queue_of_vertices.push(neighbor); + } + } + } + } + +}; + +/** + * A structure that holds a rooted tree and allow for effecient + * queries of the lowest common ancestor of two given vertices in the tree. + */ +class LowestCommonAncestor { + public: + /** + * \brief Stores the tree and precomputs "up lifts". + * @param tree_ rooted tree. + */ + explicit LowestCommonAncestor(const RootedTree& tree_) : tree(tree_) { + populate_up(); + } + + /** + * \brief Query the structure to find the lowest common ancestor. + * Assumes that the provided numbers are valid indices of vertices. + * Iterativelly modifies ("lifts") u an v until it finnds their lowest + * common ancestor. + * @param u index of one of the queried vertex + * @param v index of the other queried vertex + * @return index of the vertex which is the lowet common ancestor of u and v + */ + int lowest_common_ancestor(int u, int v) const { + // Ensure u is the deeper (higher level) of the two vertices + if (tree.level[v] > tree.level[u]) { + std::swap(u, v); + } + + // "Lift" u to the same level as v. + int level_diff = tree.level[u] - tree.level[v]; + for (int i = 0; (1 << i) <= level_diff; ++i) { + if (level_diff & (1 << i)) { + u = up[u][i]; + } + } + assert(tree.level[u] == tree.level[v]); + + if (u == v) { + return u; + } + + // "Lift" u and v to their 2^i th ancestor if they are different + for (int i = static_cast(up[u].size()) - 1; i >= 0; --i) { + if (up[u][i] != up[v][i]) { + u = up[u][i]; + v = up[v][i]; + } + } + + // As we regressed u an v such that they cannot further be lifted so + // that their ancestor would be different, the only logical + // consequence is that their parent is the sought answer. + assert(up[u][0] == up[v][0]); + return up[u][0]; + } + + /* \brief reference to the rooted tree this structure allows to query */ + const RootedTree& tree; + /** + * \brief for every vertex stores a list of its ancestors by powers of two + * For each vertex, the first element of the corresponding list contains + * the index of its parent. The i-th element of the list is an index of + * the (2^i)-th ancestor of the vertex. + */ + std::vector< std::vector > up; + + protected: + /** + * Populate the "up" structure. See above. + */ + void populate_up() { + up.resize(tree.number_of_vertices()); + for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) { + up[vertex].push_back(tree.parent[vertex]); + } + for (int level = 0; (1 << level) < tree.number_of_vertices(); ++level) { + for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) { + // up[vertex][level + 1] = 2^(level + 1) th ancestor of vertex = + // = 2^level th ancestor of 2^level th ancestor of vertex = + // = 2^level th ancestor of up[vertex][level] + up[vertex].push_back(up[up[vertex][level]][level]); + } + } + } +}; + +} // namespace graph + +/** + * Unit tests + * @rerturns none + */ +static void tests() { + /** + * _ 3 _ + * / | \ + * 1 6 4 + * / | / \ \ + * 7 5 2 8 0 + * | + * 9 + */ + std::vector< std::pair > edges = { + {7, 1}, {1, 5}, {1, 3}, {3, 6}, {6, 2}, {2, 9}, {6, 8}, {4, 3}, {0, 4} + }; + graph::RootedTree t(edges, 3); + graph::LowestCommonAncestor lca(t); + assert(lca.lowest_common_ancestor(7, 4) == 3); + assert(lca.lowest_common_ancestor(9, 6) == 6); + assert(lca.lowest_common_ancestor(0, 0) == 0); + assert(lca.lowest_common_ancestor(8, 2) == 6); +} + +/** Main function */ +int main() { + tests(); + return 0; +} From bae4b4c14c2f3e15d67248d3eac9d7f9b725242a Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 14 Aug 2020 17:11:54 -0500 Subject: [PATCH 9/9] fix: spelling typo (#1024) --- graph/lowest_common_ancestor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/lowest_common_ancestor.cpp b/graph/lowest_common_ancestor.cpp index 497d83187..11029a5b8 100644 --- a/graph/lowest_common_ancestor.cpp +++ b/graph/lowest_common_ancestor.cpp @@ -229,7 +229,7 @@ class LowestCommonAncestor { /** * Unit tests - * @rerturns none + * @returns none */ static void tests() { /**