This documentation is automatically generated by online-judge-tools/verification-helper
#include "graph/strongly_connected_components.hpp"
#pragma once
#include <algorithm>
#include <cassert>
#include <vector>
// CUT begin
// Directed graph library to find strongly connected components (強連結成分分解)
// 0-indexed directed graph
// Complexity: O(V + E)
struct DirectedGraphSCC {
int V; // # of Vertices
std::vector<std::vector<int>> to, from;
std::vector<int> used; // Only true/false
std::vector<int> vs;
std::vector<int> cmp;
int scc_num = -1;
DirectedGraphSCC(int V = 0) : V(V), to(V), from(V), cmp(V) {}
void _dfs(int v) {
used[v] = true;
for (auto t : to[v])
if (!used[t]) _dfs(t);
vs.push_back(v);
}
void _rdfs(int v, int k) {
used[v] = true;
cmp[v] = k;
for (auto t : from[v])
if (!used[t]) _rdfs(t, k);
}
void add_edge(int from_, int to_) {
assert(from_ >= 0 and from_ < V and to_ >= 0 and to_ < V);
to[from_].push_back(to_);
from[to_].push_back(from_);
}
// Detect strongly connected components and return # of them.
// Also, assign each vertex `v` the scc id `cmp[v]` (0-indexed)
int FindStronglyConnectedComponents() {
used.assign(V, false);
vs.clear();
for (int v = 0; v < V; v++)
if (!used[v]) _dfs(v);
used.assign(V, false);
scc_num = 0;
for (int i = (int)vs.size() - 1; i >= 0; i--)
if (!used[vs[i]]) _rdfs(vs[i], scc_num++);
return scc_num;
}
// Find and output the vertices that form a closed cycle.
// output: {v_1, ..., v_C}, where C is the length of cycle,
// {} if there's NO cycle (graph is DAG)
int _c, _init;
std::vector<int> _ret_cycle;
bool _dfs_detectcycle(int now, bool b0) {
if (now == _init and b0) return true;
for (auto nxt : to[now])
if (cmp[nxt] == _c and !used[nxt]) {
_ret_cycle.emplace_back(nxt), used[nxt] = 1;
if (_dfs_detectcycle(nxt, true)) return true;
_ret_cycle.pop_back();
}
return false;
}
std::vector<int> DetectCycle() {
int ns = FindStronglyConnectedComponents();
if (ns == V) return {};
std::vector<int> cnt(ns);
for (auto x : cmp) cnt[x]++;
_c = std::find_if(cnt.begin(), cnt.end(), [](int x) { return x > 1; }) - cnt.begin();
_init = std::find(cmp.begin(), cmp.end(), _c) - cmp.begin();
used.assign(V, false);
_ret_cycle.clear();
_dfs_detectcycle(_init, false);
return _ret_cycle;
}
// After calling `FindStronglyConnectedComponents()`, generate a new graph by uniting all
// vertices belonging to the same component(The resultant graph is DAG).
DirectedGraphSCC GenerateTopologicalGraph() {
DirectedGraphSCC newgraph(scc_num);
for (int s = 0; s < V; s++)
for (auto t : to[s]) {
if (cmp[s] != cmp[t]) newgraph.add_edge(cmp[s], cmp[t]);
}
return newgraph;
}
};
// 2-SAT solver: Find a solution for `(Ai v Aj) ^ (Ak v Al) ^ ... = true`
// - `nb_sat_vars`: Number of variables
// - Considering a graph with `2 * nb_sat_vars` vertices
// - Vertices [0, nb_sat_vars) means `Ai`
// - vertices [nb_sat_vars, 2 * nb_sat_vars) means `not Ai`
struct SATSolver : DirectedGraphSCC {
int nb_sat_vars;
std::vector<int> solution;
SATSolver(int nb_variables = 0)
: DirectedGraphSCC(nb_variables * 2), nb_sat_vars(nb_variables), solution(nb_sat_vars) {}
void add_x_or_y_constraint(bool is_x_true, int x, bool is_y_true, int y) {
assert(x >= 0 and x < nb_sat_vars);
assert(y >= 0 and y < nb_sat_vars);
if (!is_x_true) x += nb_sat_vars;
if (!is_y_true) y += nb_sat_vars;
add_edge((x + nb_sat_vars) % (nb_sat_vars * 2), y);
add_edge((y + nb_sat_vars) % (nb_sat_vars * 2), x);
}
// Solve the 2-SAT problem. If no solution exists, return `false`.
// Otherwise, dump one solution to `solution` and return `true`.
bool run() {
FindStronglyConnectedComponents();
for (int i = 0; i < nb_sat_vars; i++) {
if (cmp[i] == cmp[i + nb_sat_vars]) return false;
solution[i] = cmp[i] > cmp[i + nb_sat_vars];
}
return true;
}
};
#line 2 "graph/strongly_connected_components.hpp"
#include <algorithm>
#include <cassert>
#include <vector>
// CUT begin
// Directed graph library to find strongly connected components (強連結成分分解)
// 0-indexed directed graph
// Complexity: O(V + E)
struct DirectedGraphSCC {
int V; // # of Vertices
std::vector<std::vector<int>> to, from;
std::vector<int> used; // Only true/false
std::vector<int> vs;
std::vector<int> cmp;
int scc_num = -1;
DirectedGraphSCC(int V = 0) : V(V), to(V), from(V), cmp(V) {}
void _dfs(int v) {
used[v] = true;
for (auto t : to[v])
if (!used[t]) _dfs(t);
vs.push_back(v);
}
void _rdfs(int v, int k) {
used[v] = true;
cmp[v] = k;
for (auto t : from[v])
if (!used[t]) _rdfs(t, k);
}
void add_edge(int from_, int to_) {
assert(from_ >= 0 and from_ < V and to_ >= 0 and to_ < V);
to[from_].push_back(to_);
from[to_].push_back(from_);
}
// Detect strongly connected components and return # of them.
// Also, assign each vertex `v` the scc id `cmp[v]` (0-indexed)
int FindStronglyConnectedComponents() {
used.assign(V, false);
vs.clear();
for (int v = 0; v < V; v++)
if (!used[v]) _dfs(v);
used.assign(V, false);
scc_num = 0;
for (int i = (int)vs.size() - 1; i >= 0; i--)
if (!used[vs[i]]) _rdfs(vs[i], scc_num++);
return scc_num;
}
// Find and output the vertices that form a closed cycle.
// output: {v_1, ..., v_C}, where C is the length of cycle,
// {} if there's NO cycle (graph is DAG)
int _c, _init;
std::vector<int> _ret_cycle;
bool _dfs_detectcycle(int now, bool b0) {
if (now == _init and b0) return true;
for (auto nxt : to[now])
if (cmp[nxt] == _c and !used[nxt]) {
_ret_cycle.emplace_back(nxt), used[nxt] = 1;
if (_dfs_detectcycle(nxt, true)) return true;
_ret_cycle.pop_back();
}
return false;
}
std::vector<int> DetectCycle() {
int ns = FindStronglyConnectedComponents();
if (ns == V) return {};
std::vector<int> cnt(ns);
for (auto x : cmp) cnt[x]++;
_c = std::find_if(cnt.begin(), cnt.end(), [](int x) { return x > 1; }) - cnt.begin();
_init = std::find(cmp.begin(), cmp.end(), _c) - cmp.begin();
used.assign(V, false);
_ret_cycle.clear();
_dfs_detectcycle(_init, false);
return _ret_cycle;
}
// After calling `FindStronglyConnectedComponents()`, generate a new graph by uniting all
// vertices belonging to the same component(The resultant graph is DAG).
DirectedGraphSCC GenerateTopologicalGraph() {
DirectedGraphSCC newgraph(scc_num);
for (int s = 0; s < V; s++)
for (auto t : to[s]) {
if (cmp[s] != cmp[t]) newgraph.add_edge(cmp[s], cmp[t]);
}
return newgraph;
}
};
// 2-SAT solver: Find a solution for `(Ai v Aj) ^ (Ak v Al) ^ ... = true`
// - `nb_sat_vars`: Number of variables
// - Considering a graph with `2 * nb_sat_vars` vertices
// - Vertices [0, nb_sat_vars) means `Ai`
// - vertices [nb_sat_vars, 2 * nb_sat_vars) means `not Ai`
struct SATSolver : DirectedGraphSCC {
int nb_sat_vars;
std::vector<int> solution;
SATSolver(int nb_variables = 0)
: DirectedGraphSCC(nb_variables * 2), nb_sat_vars(nb_variables), solution(nb_sat_vars) {}
void add_x_or_y_constraint(bool is_x_true, int x, bool is_y_true, int y) {
assert(x >= 0 and x < nb_sat_vars);
assert(y >= 0 and y < nb_sat_vars);
if (!is_x_true) x += nb_sat_vars;
if (!is_y_true) y += nb_sat_vars;
add_edge((x + nb_sat_vars) % (nb_sat_vars * 2), y);
add_edge((y + nb_sat_vars) % (nb_sat_vars * 2), x);
}
// Solve the 2-SAT problem. If no solution exists, return `false`.
// Otherwise, dump one solution to `solution` and return `true`.
bool run() {
FindStronglyConnectedComponents();
for (int i = 0; i < nb_sat_vars; i++) {
if (cmp[i] == cmp[i + nb_sat_vars]) return false;
solution[i] = cmp[i] > cmp[i + nb_sat_vars];
}
return true;
}
};