The Aspvall-Plass-Tarjan Algorithm is an algorithm that checks if
and finds such a sequence if there exists for and in time and space.
Algorithm
Lemma
- Let .
Lemma
Let , then
Proof
Applying the lemma yields
Lemma
Proof
Applying the lemma yields
Lemma
Let denote the set of the strongly connected components of , and let be a topological sort of the strongly connected components by their reachability, and let denote the position of the strongly connected component containing in .
Then, if ,
satisfies .
Proof
- Apply an appropriate strongly-connected-component-finding algorithm (e.g., Tarjan’s Strongly Connected Components Algorithm, Kosaraju’s Algorithm) to find the strongly connected components of and apply Kahn’s Algorithm to find a topological sort of the strongly connected components by their reachability.
- Apply the lemma to check if there exists a solution and apply the lemma to find one if there exists.
This algorithm solves the problem in time and space.
std::optional<std::vector<bool>> aspvall_plass_tarjan(int n, int m, const std::vector<int> &u, const std::vector<bool> &a, const std::vector<int> &v, const std::vector<bool> &b) {
std::vector<int> s(2 * m), t(2 * m);
for (int i = 0; i < m; i++) {
s[2 * i] = u[i] << 1 | !a[i], t[2 * i] = v[i] << 1 | b[i];
s[2 * i + 1] = v[i] << 1 | !b[i], t[2 * i + 1] = u[i] << 1 | a[i];
}
auto scc = tarjan_scc(2 * n, 2 * m, s, t);
std::vector<int> topo(2 * n);
for (int i = 0; i < int(scc.size()); i++) {
for (int j : scc[i]) {
topo[j] = scc.size() - i - 1;
}
}
if (std::ranges::any_of(std::views::iota(0, n), [&](int i) -> bool {
return topo[i << 1 | true] == topo[i << 1 | false];
})) {
return std::nullopt;
}
return std::ranges::to<std::vector>(std::views::iota(0, n) | std::views::transform([&](int i) -> bool {
return topo[i << 1 | true] > topo[i << 1 | false];
}));
}