#ifndef TARJAN_H_ #define TARJAN_H_ #include "graph/scc.h" #include #include #include using namespace graph; namespace algo { template class Tarjan { public: Tarjan() = default; Tarjan(std::map> adjMatrix) : adjMatrix(adjMatrix) {} auto execute(); void strongConnect(const T& u); void setGraph(std::map> adjMatrix); private: std::map> adjMatrix; std::stack S; std::int16_t index = 0; std::vector> SCCs; T cid; struct Vertex { int index = -1; int lowlink = -1; bool onStack = false; }; std::map vmap; }; template void Tarjan::strongConnect(const T& u) { vmap[u].index = vmap[u].lowlink = index++; S.push(u); vmap[u].onStack = true; for (const auto& w : adjMatrix[u]) { if (vmap[w].index == -1) { strongConnect(w); vmap[u].lowlink = std::min(vmap[u].lowlink, vmap[w].lowlink); } else if (vmap[w].onStack) { vmap[u].lowlink = std::min(vmap[u].lowlink, vmap[w].index); } } // If u is a root node, pop the stack and generate an SCC if (vmap[u].lowlink == vmap[u].index) { std::map> scc; bool finished = false; cid = S.top(); do { const auto w = S.top(); S.pop(); vmap[w].onStack = false; scc[w] = adjMatrix[w]; finished = (w == u); } while (!finished); SCCs.push_back({ scc, static_cast(cid) }); } } template auto Tarjan::execute() { for (const auto& u : std::views::keys(adjMatrix)) { if (vmap[u].index == -1) strongConnect(u); } return SCCs; } template void Tarjan::setGraph(std::map> adjMatrix) { this->adjMatrix = adjMatrix; } } // namespace algo #endif