lowest_common_ancestor.cpp 8.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
/**
 *
 * \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:
 * <br/>  Tree:
 * <pre>
 *             _  3  _
 *          /     |     \
 *        1       6       4
 *      / |     /   \       \
 *    7   5   2       8       0
 *            |
 *            9
 * </pre>
 *
 * <br/>  lowest_common_ancestor(7, 4) = 3
 * <br/>  lowest_common_ancestor(9, 6) = 6
 * <br/>  lowest_common_ancestor(0, 0) = 0
 * <br/>  lowest_common_ancestor(8, 2) = 6
 *
 *   The query is symmetrical, therefore
 *     lowest_common_ancestor(x, y) = lowest_common_ancestor(y, x)
 */

#include <iostream>
#include <utility>
#include <vector>
#include <queue>
#include <cassert>

/**
 * \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<int, int> > &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<int> > 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<int, int> > &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<int> parent;
    /** \brief Stores the distance from the root. */
    std::vector<int> 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<int>(number_of_vertices(), -1);
        level = std::vector<int>(number_of_vertices());
        parent[root] = root;
        level[root] = 0;
        std::queue<int> 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<int>(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<int> > 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
D
David Leal 已提交
232
 * @returns none
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
 */
static void tests() {
    /**
     *             _  3  _
     *          /     |     \
     *        1       6       4
     *      / |     /   \       \
     *    7   5   2       8       0
     *            |
     *            9
     */
    std::vector< std::pair<int, int> > 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;
}