diff --git a/src/classes/graph/graph.h b/src/classes/graph/graph.h index d3122a1f..18b7600d 100644 --- a/src/classes/graph/graph.h +++ b/src/classes/graph/graph.h @@ -507,7 +507,7 @@ template int64_t graph::scc() { std::unordered_map > new_adj; for(const T& x: _elements) { - for(auto & neigh: adj[x]) { + for(const auto& neigh: adj[x]) { new_adj[neigh].push_back(x); } } @@ -866,6 +866,20 @@ template class weighted_graph { } } } + + /** + * @brief helper dfs function for kosaraju's scc + */ + void dfs_scc(T start, std::unordered_map &visited, std::stack &s) { + visited[start] = true; + for(auto & x : adj[start]) { + if(visited.find(x.first) == visited.end()) { + dfs_scc(x.first, visited, s); + } + } + + s.push(start); + } }; template size_t weighted_graph::size() { @@ -1144,6 +1158,59 @@ std::vector> weighted_graph::bridge(T start) { return bridges; } +template +int64_t weighted_graph::scc() { + if (this -> size() == 0) { + return 0; + } + + std::unordered_map visited; + std::stack s; + + for(const T& x : _elements) { + if(visited.find(x) == visited.end()) { + dfs_scc(x, visited, s); + } + } + + std::unordered_map > new_adj; + for(const T& x: _elements) { + for(const auto& neigh: adj[x]) { + new_adj[neigh.first].push_back(x); + } + } + + int64_t scc = 0; + visited.clear(); + + auto dfs_new = [&](T start) -> void { + std::stack _s; + _s.push(start); + visited[start] = true; + while(!_s.empty()) { + T current = _s.top(); + _s.pop(); + for(auto & x: new_adj[current]) { + if (visited.find(x) == visited.end()) { + _s.push(x); + visited[x] = true; + } + } + } + }; + + while(!s.empty()) { + T current = s.top(); + s.pop(); + if (visited.find(current) == visited.end()) { + dfs_new(current); + scc++; + } + } + + return scc; +} + template bool weighted_graph::connected() { std::unordered_map visited; bool check = 0; diff --git a/tests/graph/weighted_graph.cc b/tests/graph/weighted_graph.cc index d16a86b9..55a00f49 100644 --- a/tests/graph/weighted_graph.cc +++ b/tests/graph/weighted_graph.cc @@ -296,6 +296,57 @@ TEST_CASE("Testing shortest path algorithm [2]") { REQUIRE(g.shortest_path(1, 7) == 56); } +TEST_CASE("Testing scc function for weighted graph class") { + weighted_graph g("directed"); + g.add_edge(0, 1, 50); + g.add_edge(1, 2, 50); + g.add_edge(2, 0, 50); + g.add_edge(1, 3, 50); + g.add_edge(3, 4, 50); + g.add_edge(4, 3, 50); + + REQUIRE(g.scc() == 2); + + weighted_graph g2("undirected"); + REQUIRE(g2.scc() == 0); + + g2.add_edge(0, 1, 5); + g2.add_edge(1, 2, 5); + g2.add_edge(2, 0, 5); + g2.add_edge(3, 4, 5); + g2.add_edge(4, 5, 5); + g2.add_edge(5, 3, 5); + g2.add_edge(3, 6, 5); + g2.add_edge(1, 3, 5); + + REQUIRE(g2.scc() == 1); + + weighted_graph t("directed"); + t.add_edge('a', 'b', 5); + t.add_edge('b', 'c', 5); + t.add_edge('c', 'a', 5); + t.add_edge('b', 'd', 5); + t.add_edge('d', 'e', 5); + t.add_edge('e', 'd', 5); + + REQUIRE(t.scc() == 2); + + weighted_graph g3("directed"); + g3.add_edge(0, 1, 5); + g3.add_edge(1, 2, 5); + g3.add_edge(2, 0, 5); + g3.add_edge(1, 3, 5); + g3.add_edge(3, 4, 5); + g3.add_edge(4, 5, 5); + g3.add_edge(5, 3, 5); + g3.add_edge(3, 6, 5); + g3.add_edge(6, 7, 5); + g3.add_edge(6, 8, 5); + g3.add_edge(8, 6, 5); + + REQUIRE(g3.scc() == 4); +} + #define GRAPH_VISUALIZATION_H #ifdef GRAPH_VISUALIZATION_H