diff options
Diffstat (limited to 'graph/test')
| -rw-r--r-- | graph/test/LCA_sparse.cpp | 63 | ||||
| -rw-r--r-- | graph/test/binary_lifting.cpp | 67 | ||||
| -rw-r--r-- | graph/test/util.cpp | 60 |
3 files changed, 190 insertions, 0 deletions
diff --git a/graph/test/LCA_sparse.cpp b/graph/test/LCA_sparse.cpp new file mode 100644 index 0000000..c8b0017 --- /dev/null +++ b/graph/test/LCA_sparse.cpp @@ -0,0 +1,63 @@ +#include "util.cpp" +#define all(X) begin(X), end(X) +#define sz ssize +#include "../../datastructures/sparseTable.cpp" +#include "../LCA_sparse.cpp" + +void test(vector<vector<int>> &adj, int root) { + int n = adj.size(); + + vector<int> parent(n); + function<void(int,int)> dfs = [&](int u, int p) { + parent[u] = p; + for (int v: adj[u]) if (v != p) dfs(v, u); + }; + dfs(root, -1); + + function<bool(int, int)> is_ancestor = [&](int u, int v) { + while (v != -1 && u != v) v = parent[v]; + return u == v; + }; + function<int(int)> depth = [&](int v) { + int r = 0; + while ((v = parent[v]) != -1) r++; + return r; + }; + + LCA lca; + lca.init(adj, root); + for (int i = 0; i < n; i++) assert(lca.getDepth(i) == depth(i)); + for (int i = 0; i < 1000; i++) { + int u = util::randint(n); + int v = util::randint(n); + int l = lca.getLCA(u, v); + assert(is_ancestor(l, u)); + assert(is_ancestor(l, v)); + for (int p = parent[l]; int c: adj[l]) { + if (c == p) continue; + assert(!is_ancestor(c, u) || !is_ancestor(c, v)); + } + } +} + +int main() { + { + // Single vertex + vector<vector<int>> adj(1); + test(adj, 0); + } + { + // Path + vector<vector<int>> adj = util::path(100); + int left = 0, mid = 40, right = 99; + util::shuffle_graph(adj, left, mid, right); + test(adj, left); + test(adj, mid); + test(adj, right); + } + { + // Random + vector<vector<int>> adj = util::random_tree(1000); + test(adj, 0); + } +} diff --git a/graph/test/binary_lifting.cpp b/graph/test/binary_lifting.cpp new file mode 100644 index 0000000..05b903a --- /dev/null +++ b/graph/test/binary_lifting.cpp @@ -0,0 +1,67 @@ +#include "util.cpp" +#include "../binary_lifting.cpp" + +void test(vector<vector<int>> &adj, int root) { + int n = adj.size(); + + vector<int> parent(n); + function<void(int,int)> dfs = [&](int u, int p) { + parent[u] = p; + for (int v: adj[u]) if (v != p) dfs(v, u); + }; + dfs(root, -1); + + function<bool(int, int)> is_ancestor = [&](int u, int v) { + while (v != -1 && u != v) v = parent[v]; + return u == v; + }; + function<int(int)> depth = [&](int v) { + int r = 0; + while ((v = parent[v]) != -1) r++; + return r; + }; + + Lift lift(adj, root); + for (int i = 0; i < n; i++) assert(lift.depth(i) == depth(i)); + for (int i = 0; i < 1000; i++) { + int v = util::randint(n); + int d = util::randint(n); + int u = lift.lift(v, d); + assert(is_ancestor(u, v)); + if (d <= depth(v)) assert(depth(u) == d); + else assert(u == v); + } + for (int i = 0; i < 1000; i++) { + int u = util::randint(n); + int v = util::randint(n); + int lca = lift.lca(u, v); + assert(is_ancestor(lca, u)); + assert(is_ancestor(lca, v)); + for (int p = parent[lca]; int c: adj[lca]) { + if (c == p) continue; + assert(!is_ancestor(c, u) || !is_ancestor(c, v)); + } + } +} + +int main() { + { + // Single vertex + vector<vector<int>> adj(1); + test(adj, 0); + } + { + // Path + vector<vector<int>> adj = util::path(100); + int left = 0, mid = 40, right = 99; + util::shuffle_graph(adj, left, mid, right); + test(adj, left); + test(adj, mid); + test(adj, right); + } + { + // Random + vector<vector<int>> adj = util::random_tree(1000); + test(adj, 0); + } +} diff --git a/graph/test/util.cpp b/graph/test/util.cpp new file mode 100644 index 0000000..8c14b5c --- /dev/null +++ b/graph/test/util.cpp @@ -0,0 +1,60 @@ + +namespace util { + +void shuffle_adj_lists(vector<vector<int>> &adj) { + for (auto &a: adj) ranges::shuffle(a, rd); +} + +vector<vector<int>> random_tree(int n) { + vector<vector<int>> adj(n); + + vector<vector<int>> components(n); + for (int i = 0; i < n; i++) components[i].push_back(i); + while (components.size() > 1) { + int c1 = randint(components.size()); + int c2 = randint(components.size()-1); + c2 += (c2 >= c1); + + int v1 = components[c1][randint(components[c1].size())]; + int v2 = components[c2][randint(components[c2].size())]; + + adj[v1].push_back(v2); + adj[v2].push_back(v1); + + if (components[c1].size() < components[c2].size()) swap(c1, c2); + for (int v: components[c2]) components[c1].push_back(v); + swap(components[c2], components.back()); + components.pop_back(); + } + + shuffle_adj_lists(adj); + return adj; +} + +vector<vector<int>> path(int n) { + vector<vector<int>> adj(n); + for (int i = 1; i < n; i++) { + adj[i-1].push_back(i); + adj[i].push_back(i-1); + } + return adj; +} + +template<typename... Ts> +void shuffle_graph(vector<vector<int>> &adj, Ts &...vertex) { + int n = adj.size(); + vector<int> perm(n); + iota(perm.begin(), perm.end(), 0); + ranges::shuffle(perm, rd); + + vector<vector<int>> new_adj(n); + for (int i = 0; i < n; i++) { + auto &a = new_adj[perm[i]] = move(adj[i]); + for (int &v: a) v = perm[v]; + } + adj = move(new_adj); + shuffle_adj_lists(adj); + ((vertex = perm[vertex]), ...); +} + +} |
