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

  1. Let .

Lemma

Let , then

Lemma

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 .

  1. 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.
  2. 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];
	}));
}