diff --git a/algorithm/frigioni.h b/algorithm/frigioni.h index ac4aceb..4330a1f 100644 --- a/algorithm/frigioni.h +++ b/algorithm/frigioni.h @@ -3,12 +3,14 @@ #include "algorithm/roditty_zwick.h" #include "algorithm/tarjan.h" -#include "tree/breadth_first_tree.h" +#include "graph/breadth_first_tree.h" +#include "algorithm/decremental_scc.h" #include +#include +#include using namespace graph; -using namespace tree; namespace algo { @@ -25,30 +27,59 @@ public: private: Digraph G; - // Connect each vertex with its representative SCC - std::map> TC; + // Transitive closure matrix, used to answer reachability queries in O(1) + std::map> TC; - // Reachability trees - std::map, std::set>> RT; + // Connect each vertex with its representative SCC + std::map> C; + + // Each scc's representative vertex reachability tree + std::map> RT; // Incoming / Outgoing / Internal edges struct Edges { - std::forward_list Ein; - std::forward_list Eout; - std::forward_list Eint; + std::set> in; + std::set> inc; + std::set> out; }; - std::map, Edges> E; + std::map E; }; - template void Frigioni::init() { + auto SCCs = Tarjan(G.adjMatrix).execute(); + for (auto& scc : SCCs) { + RT[scc.id] = BreadthFirstTree(G, scc.id); + for (const auto& u : G.vertices()) { + C[u] = scc; + for (const auto& v : G.adjMatrix[u]) { + TC[u][v] = false; + if (scc.member(u)) { + if (scc.member(v)) + E[scc.id].in.insert(std::make_pair(u, v)); + else + E[scc.id].out.insert(std::make_pair(u, v)); + } else if (scc.member(v)) { + E[scc.id].inc.insert(std::make_pair(u, v)); + } + } + } + } + for (auto& scc : SCCs) { + for (const auto& u : G.vertices()) { + if (scc.member(u)) { + for (const auto& v : RT[scc.id].vertices()) { + TC[u][v] = true; + } + } + } + } } template bool Frigioni::query(const T& u, const T& v) { - return TC[u] == TC[v]; + return TC[u][v]; } template diff --git a/test/decremental_test.cc b/test/roditty_zwick_test.cc similarity index 96% rename from test/decremental_test.cc rename to test/roditty_zwick_test.cc index 96a20fd..b41179f 100644 --- a/test/decremental_test.cc +++ b/test/roditty_zwick_test.cc @@ -6,9 +6,9 @@ using namespace graph; -TEST_SUITE("Decremental algorithms") { +TEST_SUITE("Decremental Algorithm") { - TEST_CASE("Decremental maintenance of SCCs") { + TEST_CASE("DecrementalSCC") { // 1 --> 2 --> 3 --> 1 // 3 --> 4 --> 5 --> 3 // 2 --> 6 --> 7 --> 8 --> 6 @@ -112,7 +112,7 @@ TEST_SUITE("Decremental algorithms") { } } - TEST_CASE("Frigioni 1") { + TEST_CASE("Frigioni") { // 1 --> 2 --> 4 --> 6 --> 8 --> 9 --> 5 // 4 --> 5 --> 7 --> 8 // 5 --> 6 @@ -141,15 +141,16 @@ TEST_SUITE("Decremental algorithms") { algo::Frigioni frigioni(G); frigioni.init(); - /* + SUBCASE("Frigioni::query") { CHECK_EQ(frigioni.query(1, 9), true); CHECK_EQ(frigioni.query(2, 8), true); CHECK_EQ(frigioni.query(3, 9), true); + CHECK_EQ(frigioni.query(9, 5), true); CHECK_EQ(frigioni.query(4, 3), false); CHECK_EQ(frigioni.query(5, 4), false); CHECK_EQ(frigioni.query(6, 1), false); - }*/ + } /* SUBCASE("Frigioni::remove") { frigioni.remove(4, 6);