This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub fffelix-huang/CP-stuff
#include "library/random/graph-generator.hpp"
int n; bool is_tree, weighted; long long low, high; int OFFSET = 0; // 0-based GraphGenerator::generate(n, is_tree, weighted, low, high).print(OFFSET);
https://nyaannyaan.github.io/library/random_graph/gen.hpp
#pragma once #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <set> #include <cassert> #include "random.hpp" namespace felix { namespace GraphGenerator { struct Graph { struct Edge { int u, v; long long w; Edge(int x, int y, long long z = 1) : u(x), v(y), w(z) {} }; int n, m = 0; bool weighted; std::vector<Edge> edges; std::vector<std::vector<int>> g; Graph(int _n = 0, bool _weighted = false) : n(_n), weighted(_weighted), g(_n) {} void add_edge(int u, int v, long long w = -1) { g[u].push_back(edges.size()); edges.emplace_back(u, v, w); m += 1; } void add_undirected_edge(int u, int v, long long w = -1) { int x = std::min(u, v); int y = std::max(u, v); add_edge(x, y, w); } std::vector<std::vector<Edge>> adjacency_list(bool directed = false) { std::vector<std::vector<Edge>> h(n); for(auto& [u, v, w] : edges) { h[u].emplace_back(u, v, w); if(!directed) { h[v].emplace_back(v, u, w); } } return h; } std::vector<std::vector<long long>> adjacency_matrix(bool directed = false) { std::vector<std::vector<long long>> h(n, std::vector<long long>(n)); for(auto& [u, v, w] : edges) { h[u][v] = w; if(!directed) { h[v][u] = w; } } return h; } void print_matrix(bool directed = false) { auto h = adjacency_matrix(directed); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { std::cout << h[i][j] << " \n"[j == n - 1]; } } } void print(int OFFSET = 0) { std::cout << n << " " << m << "\n"; for(auto& [u, v, w] : edges) { std::cout << u + OFFSET << " " << v + OFFSET; if(weighted) { std::cout << " " << w; } std::cout << "\n"; } } }; long long w_low = 1, w_high = 1; void set_weight(bool weighted, long long low, long long high) { if(!weighted) { low = high = 1; } w_low = low; w_high = high; } void add_edge(Graph& g, int u, int v) { long long w = rnd.next(w_low, w_high); g.add_undirected_edge(u, v, w); } Graph tree(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 1; i < n; i++) { add_edge(g, order[rnd.next(0, i - 1)], order[i]); } assert(g.m == n - 1); return g; } Graph path(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 0; i < n - 1; i++) { add_edge(g, order[i], order[i + 1]); } assert(g.m == n - 1); return g; } Graph star(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 1; i < n; i++) { add_edge(g, order[0], order[i]); } assert(g.m == n - 1); return g; } Graph perfect(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); for(int i = 0; i < n; i++) { for(int j = i + 1; j < n; j++) { add_edge(g, i, j); } } return g; } Graph simple(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 0; i < n; i++) { for(int j = i + 1; j < n; j++) { if(rnd.next(0, 1)) { add_edge(g, i, j); } } } return g; } Graph namori(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); add_edge(g, 0, rnd.next(1, n - 1)); for(int i = 1; i < n; i++) { add_edge(g, i, rnd.next(0, i - 1)); } return g; } Graph sparse(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 0) { return g; } int m = rnd.next(0, n - 1); std::set<std::pair<int, int>> edges; while((int) edges.size() < m) { int u = rnd.next(0, n - 1); int v = rnd.next(0, n - 1); if(u >= v) { continue; } edges.emplace(u, v); } for(auto [u, v] : edges) { add_edge(g, u, v); } return g; } Graph connected(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 1) { return g; } std::set<std::pair<int, int>> s; auto perm = rnd.perm(n); for(int i = 1; i < n; i++) { int u = perm[rnd.next(i)]; int v = perm[i]; add_edge(g, u, v); s.emplace(std::min(u, v), std::max(u, v)); } int extra = rnd.next(n, 10 * n); for(int i = 0; i < extra; i++) { int u = rnd.next(n - 1); int v = rnd.next(u + 1, n - 1); if(s.count({u, v})) { continue; } s.emplace(u, v); add_edge(g, u, v); } return g; } Graph bipartite(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 1) { return g; } auto perm = rnd.perm(n); int l_cnt = rnd.next(1, n - 1); auto lv = std::vector<int>(perm.begin(), perm.begin() + l_cnt); auto rv = std::vector<int>(perm.begin() + l_cnt, perm.end()); for(auto u : lv) { for(auto v : rv) { if(rnd.next(0, 1)) { add_edge(g, u, v); } } } return g; } Graph generate(int n, bool is_tree = false, bool weighted = false, long long w_min = 1, long long w_max = 1) { using F = std::function<Graph(int, bool, long long, long long)>; std::vector<F> f{tree, path, star, perfect, simple, namori, sparse, bipartite}; int mx = (is_tree ? 2 : (int) f.size()); return f[rnd.next(0, mx)](n, weighted, w_min, w_max); } } // namespace GraphGenerator } // namespace felix
#line 2 "library/random/graph-generator.hpp" #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <set> #include <cassert> #line 4 "library/random/random.hpp" #include <cstring> #include <array> #line 7 "library/random/random.hpp" #include <numeric> #include <climits> #include <string> #line 2 "library/random/splitmix64.hpp" #include <chrono> namespace felix { namespace internal { // http://xoshiro.di.unimi.it/splitmix64.c struct splitmix64_hash { static unsigned long long splitmix64(unsigned long long x) { x += 0x9e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31); } unsigned long long operator()(unsigned long long x) const { static const unsigned long long FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } }; } // namespace internal } // namespace felix #line 11 "library/random/random.hpp" namespace felix { struct random_t { public: explicit random_t(unsigned long long seed = 3905348978240129619LL) { set_seed(seed); } void set_seed(unsigned long long seed) { for(int i = 0; i < 4; i++) { s[i] = internal::splitmix64_hash::splitmix64(seed); seed += 0x9e3779b97f4a7c15; } } // [0, n) unsigned long long next(unsigned long long n) { const unsigned long long LIMIT = std::numeric_limits<unsigned long long>::max() / n * n; unsigned long long r; do { r = next(); } while(r >= LIMIT); return r % n; } // [l, r] template<class T> T next(T l, T r) { assert(l <= r); return T(l + next(r - l + 1ULL)); } template<class Iter> void shuffle(Iter l, Iter r) { if(l == r) { return; } int pos = 0; for(auto it = l + 1; it != r; it++) { pos += 1; int j = next(pos + 1); if(j != pos) { std::iter_swap(it, l + j); } } } // [0, n) std::vector<int> perm(int n) { std::vector<int> a(n); std::iota(a.begin(), a.end(), 0); shuffle(a.begin(), a.end()); return a; } // [l, r] template<class T> std::vector<T> distinct(int size, T l, T r) { std::vector<T> result; if(size == 0) { return result; } assert(l <= r); assert(size > 0); unsigned long long n = r - l + 1; assert(size <= n); double expected = 0; for(int i = 1; i <= size; i++) { expected += double(n) / double(n - i + 1); } if(expected < (double) n) { std::set<T> s; while((int) s.size() < size) { T val = T(next(l, r)); if(s.insert(val).second) { result.push_back(val); } } } else { std::vector<T> p(perm(n)); for(auto& x : p) { x += l; } result.insert(result.end(), p.begin(), p.begin() + size); } return result; } std::string string(int n, char min_char = 'a', char max_char = 'z') { std::string s(n, '_'); for(int i = 0; i < n; i++) { s[i] = next(min_char, max_char); } return s; } private: std::array<unsigned long long, 4> s; static unsigned long long rotl(const unsigned long long x, int k) { return (x << k) | (x >> (64 - k)); } unsigned long long next() { const unsigned long long result = rotl(s[1] * 5, 7) * 9; const unsigned long long t = s[1] << 17; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = rotl(s[3], 45); return result; } } rnd; } // namespace felix #line 9 "library/random/graph-generator.hpp" namespace felix { namespace GraphGenerator { struct Graph { struct Edge { int u, v; long long w; Edge(int x, int y, long long z = 1) : u(x), v(y), w(z) {} }; int n, m = 0; bool weighted; std::vector<Edge> edges; std::vector<std::vector<int>> g; Graph(int _n = 0, bool _weighted = false) : n(_n), weighted(_weighted), g(_n) {} void add_edge(int u, int v, long long w = -1) { g[u].push_back(edges.size()); edges.emplace_back(u, v, w); m += 1; } void add_undirected_edge(int u, int v, long long w = -1) { int x = std::min(u, v); int y = std::max(u, v); add_edge(x, y, w); } std::vector<std::vector<Edge>> adjacency_list(bool directed = false) { std::vector<std::vector<Edge>> h(n); for(auto& [u, v, w] : edges) { h[u].emplace_back(u, v, w); if(!directed) { h[v].emplace_back(v, u, w); } } return h; } std::vector<std::vector<long long>> adjacency_matrix(bool directed = false) { std::vector<std::vector<long long>> h(n, std::vector<long long>(n)); for(auto& [u, v, w] : edges) { h[u][v] = w; if(!directed) { h[v][u] = w; } } return h; } void print_matrix(bool directed = false) { auto h = adjacency_matrix(directed); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { std::cout << h[i][j] << " \n"[j == n - 1]; } } } void print(int OFFSET = 0) { std::cout << n << " " << m << "\n"; for(auto& [u, v, w] : edges) { std::cout << u + OFFSET << " " << v + OFFSET; if(weighted) { std::cout << " " << w; } std::cout << "\n"; } } }; long long w_low = 1, w_high = 1; void set_weight(bool weighted, long long low, long long high) { if(!weighted) { low = high = 1; } w_low = low; w_high = high; } void add_edge(Graph& g, int u, int v) { long long w = rnd.next(w_low, w_high); g.add_undirected_edge(u, v, w); } Graph tree(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 1; i < n; i++) { add_edge(g, order[rnd.next(0, i - 1)], order[i]); } assert(g.m == n - 1); return g; } Graph path(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 0; i < n - 1; i++) { add_edge(g, order[i], order[i + 1]); } assert(g.m == n - 1); return g; } Graph star(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 1; i < n; i++) { add_edge(g, order[0], order[i]); } assert(g.m == n - 1); return g; } Graph perfect(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); for(int i = 0; i < n; i++) { for(int j = i + 1; j < n; j++) { add_edge(g, i, j); } } return g; } Graph simple(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); auto order = rnd.perm(n); for(int i = 0; i < n; i++) { for(int j = i + 1; j < n; j++) { if(rnd.next(0, 1)) { add_edge(g, i, j); } } } return g; } Graph namori(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); add_edge(g, 0, rnd.next(1, n - 1)); for(int i = 1; i < n; i++) { add_edge(g, i, rnd.next(0, i - 1)); } return g; } Graph sparse(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 0) { return g; } int m = rnd.next(0, n - 1); std::set<std::pair<int, int>> edges; while((int) edges.size() < m) { int u = rnd.next(0, n - 1); int v = rnd.next(0, n - 1); if(u >= v) { continue; } edges.emplace(u, v); } for(auto [u, v] : edges) { add_edge(g, u, v); } return g; } Graph connected(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 1) { return g; } std::set<std::pair<int, int>> s; auto perm = rnd.perm(n); for(int i = 1; i < n; i++) { int u = perm[rnd.next(i)]; int v = perm[i]; add_edge(g, u, v); s.emplace(std::min(u, v), std::max(u, v)); } int extra = rnd.next(n, 10 * n); for(int i = 0; i < extra; i++) { int u = rnd.next(n - 1); int v = rnd.next(u + 1, n - 1); if(s.count({u, v})) { continue; } s.emplace(u, v); add_edge(g, u, v); } return g; } Graph bipartite(int n, bool weighted = false, long long w_min = 1, long long w_max = 1) { set_weight(weighted, w_min, w_max); Graph g(n, weighted); if(n == 1) { return g; } auto perm = rnd.perm(n); int l_cnt = rnd.next(1, n - 1); auto lv = std::vector<int>(perm.begin(), perm.begin() + l_cnt); auto rv = std::vector<int>(perm.begin() + l_cnt, perm.end()); for(auto u : lv) { for(auto v : rv) { if(rnd.next(0, 1)) { add_edge(g, u, v); } } } return g; } Graph generate(int n, bool is_tree = false, bool weighted = false, long long w_min = 1, long long w_max = 1) { using F = std::function<Graph(int, bool, long long, long long)>; std::vector<F> f{tree, path, star, perfect, simple, namori, sparse, bipartite}; int mx = (is_tree ? 2 : (int) f.size()); return f[rnd.next(0, mx)](n, weighted, w_min, w_max); } } // namespace GraphGenerator } // namespace felix