5#ifdef ENABLE_GRAPH_VISUALIZATION
6#include "../../visualization/graph_visual/graph_visualization.h"
21#include <unordered_map>
22#include <unordered_set>
31template <
typename T>
class graph {
39 graph(std::string _type, std::vector<std::pair<T, std::vector<T>>> _adj = {}) {
41 if (_type ==
"directed" || _type ==
"undirected") {
44 throw std::invalid_argument(
"Can't recognize the type of graph");
47 for (
size_t i = 0; i < _adj.size(); i++) {
48 for (T& neigh : _adj[i].second) {
49 this->
add_edge(_adj[i].first, neigh);
53 }
catch (std::invalid_argument& e) {
54 std::cerr << e.what() <<
'\n';
64 graph(
const graph& g) : adj(g.adj), _elements(g._elements), _type(g._type) {}
74 _elements = g._elements;
90 if (_type ==
"undirected") {
108 if (_elements.find(start) == _elements.end()) {
111 for (T& x : adj[start]) {
132 bool empty() {
return _elements.empty(); }
145 std::vector<T>
dfs(T start);
152 std::vector<T>
bfs(T start);
184 std::vector<std::vector<T>>
bridge(T start);
221 for (T& x : elements) {
234 std::unordered_map<T, std::vector<T>> adj;
235 std::unordered_set<T> _elements;
241 void dfs_bridge(T start, T parent, int64_t& time, std::unordered_map<T, bool>& visited,
242 std::unordered_map<T, int64_t>& in, std::unordered_map<T, int64_t>& out,
243 std::vector<std::vector<T>>& bridges) {
244 visited[start] =
true;
245 in[start] = out[start] = time++;
246 for (T& x : adj[start]) {
248 if (visited.find(x) == visited.end()) {
249 dfs_bridge(x, start, time, visited, in, out, bridges);
250 if (out[x] > in[start]) {
251 bridges.push_back({x, start});
254 out[start] = std::min(out[start], out[x]);
262 void dfs_scc(T start, std::unordered_map<T, bool>& visited, std::stack<T>& s) {
263 visited[start] =
true;
264 for (
auto& x : adj[start]) {
265 if (visited.find(x) == visited.end()) {
266 dfs_scc(x, visited, s);
275 return _elements.size();
280 if (this->
empty() || _elements.find(start) == _elements.end()) {
284 std::unordered_map<T, bool> visited;
286 visited[start] =
true;
289 path.push_back(current);
291 for (T& x : adj[current]) {
292 if (visited.find(x) == visited.end()) {
303 if (this->
empty() || _elements.find(start) == _elements.end()) {
307 std::unordered_map<T, bool> visited;
309 visited[start] =
true;
311 int64_t
size = q.size();
312 for (int64_t i = 0; i <
size; i++) {
313 T current = q.front();
314 path.push_back(current);
316 for (T& x : adj[current]) {
317 if (visited.find(x) == visited.end()) {
328 auto explore = [&](std::unordered_map<T, bool>& visited, T element) ->
void {
331 visited[element] =
true;
333 T current = q.front();
335 for (T& x : adj[current]) {
336 if (visited.find(x) == visited.end()) {
343 size_t n = _elements.size();
345 std::unordered_map<T, bool> visited;
346 for (T x : _elements) {
347 if (visited.find(x) == visited.end()) {
356 std::unordered_map<T, int> indeg;
360 for (T x : _elements) {
361 for (T& y : adj[x]) {
366 for (T x : _elements) {
373 T current = q.front();
376 for (T& x : adj[current]) {
377 if (--indeg[x] == 0) {
386 std::vector<T> top_sort;
387 std::unordered_map<T, bool> visited;
388 std::unordered_map<T, int64_t> indeg;
389 for (T x : _elements) {
390 for (T& y : adj[x]) {
396 for (T x : _elements) {
404 T current = q.front();
406 top_sort.push_back(current);
407 for (T& x : adj[current]) {
408 if (visited.find(x) == visited.end()) {
409 if (--indeg[x] == 0) {
421 std::unordered_map<T, int> color;
422 std::queue<std::pair<T, int>> q;
424 for (T x : _elements) {
425 if (color.find(x) == color.end()) {
429 std::pair<T, int> current = q.front();
432 int col = current.second;
433 for (T& x : adj[v]) {
434 if (color.find(x) != color.end() && color[x] == col) {
437 if (color.find(x) == color.end()) {
438 color[x] = (col) ? 0 : 1;
439 q.push({x, color[x]});
450 std::vector<std::vector<T>> bridges;
451 std::unordered_map<T, bool> visited;
452 std::unordered_map<T, int64_t> in, out;
453 for (T x : _elements) {
457 dfs_bridge(start, -1, timer, visited, in, out, bridges);
462 std::unordered_map<T, bool> visited;
465 for (
auto& ele : adj) {
466 if (adj[ele.first].size() != 0) {
477 visited[start] =
true;
481 for (T& x : adj[current]) {
482 if (visited.find(x) == visited.end()) {
489 for (T x : _elements) {
490 if (visited.find(x) == visited.end() && adj[x].size() > 0) {
498 if (this->
size() == 0) {
502 std::unordered_map<T, bool> visited;
505 for (
const T& x : _elements) {
506 if (visited.find(x) == visited.end()) {
507 dfs_scc(x, visited, s);
511 std::unordered_map<T, std::vector<T>> new_adj;
512 for (
const T& x : _elements) {
513 for (
const auto& neigh : adj[x]) {
514 new_adj[neigh].push_back(x);
521 auto dfs_new = [&](T start) ->
void {
524 visited[start] =
true;
525 while (!_s.empty()) {
526 T current = _s.top();
528 for (
auto& x : new_adj[current]) {
529 if (visited.find(x) == visited.end()) {
540 if (visited.find(current) == visited.end()) {
555 for (
auto& el : adj) {
556 if (adj[el.first].size() & 1) {
564 return (odd) ? 1 : 2;
567#ifdef ENABLE_GRAPH_VISUALIZATION
570 if (_type ==
"directed") {
571 if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
572 for (
auto& [element, neighbors] : adj) {
573 for (T& x : neighbors) {
581 for (
auto& [element, neighbors] : adj) {
582 for (T& x : neighbors) {
583 s += std::to_string(element);
585 s += std::to_string(x);
591 if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
592 for (
auto& [element, neighbors] : adj) {
593 for (T& x : neighbors) {
601 for (
auto& [element, neighbors] : adj) {
602 for (T& x : neighbors) {
603 s += std::to_string(element);
605 s += std::to_string(x);
612 if (_type ==
"directed") {
613 digraph_visualization::visualize(s);
615 graph_visualization::visualize(s);
631 weighted_graph(std::string _type, std::vector<std::pair<std::pair<T, T>, int64_t>> _adj = {}) {
633 if (_type ==
"directed" || _type ==
"undirected") {
636 throw std::invalid_argument(
"Can't recognize the type of graph");
639 for (
size_t i = 0; i < _adj.size(); i++) {
640 this->
add_edge(_adj[i].first.first, _adj[i].first.second, _adj[i].second);
643 }
catch (std::invalid_argument& e) {
644 std::cerr << e.what() <<
'\n';
654 : adj(g.adj), _elements(g._elements), _type(g._type) {}
663 _elements = g._elements;
681 if (_type ==
"undirected") {
682 adj[u].push_back(std::make_pair(v, w));
683 adj[v].push_back(std::make_pair(u, w));
684 }
else if (_type ==
"directed") {
685 adj[u].push_back(std::make_pair(v, w));
698 if (_elements.find(start) == _elements.end()) {
701 for (std::pair<T, double>& x : adj[start]) {
702 if (x.first == end) {
721 bool empty() {
return _elements.empty(); }
734 std::vector<T>
dfs(T start);
741 std::vector<T>
bfs(T start);
774 int64_t
prim(T start);
787 std::vector<std::vector<T>>
bridge(T start);
836 for (T& x : elements) {
849 std::unordered_map<T, std::vector<std::pair<T, double>>> adj;
851 std::unordered_set<T> _elements;
856 void dfs_bridge(T start, T parent, int64_t& time, std::unordered_map<T, bool>& visited,
857 std::unordered_map<T, int64_t>& in, std::unordered_map<T, int64_t>& out,
858 std::vector<std::vector<T>>& bridges) {
859 visited[start] =
true;
860 in[start] = out[start] = time++;
861 for (std::pair<T, double>& x : adj[start]) {
862 if (x.first != parent) {
863 if (visited.find(x.first) == visited.end()) {
864 dfs_bridge(x.first, start, time, visited, in, out, bridges);
865 if (out[x.first] > in[start]) {
866 bridges.push_back({x.first, start});
869 out[start] = std::min(out[start], out[x.first]);
877 void dfs_scc(T start, std::unordered_map<T, bool>& visited, std::stack<T>& s) {
878 visited[start] =
true;
879 for (
auto& x : adj[start]) {
880 if (visited.find(x.first) == visited.end()) {
881 dfs_scc(x.first, visited, s);
890 return _elements.size();
894 if (_elements.find(start) == _elements.end()) {
895 std::cout <<
"Element: " << start <<
" is not found in the Graph" <<
'\n';
898 if (_elements.find(end) == _elements.end()) {
899 std::cout <<
"Element: " << end <<
" is not found in the Graph" <<
'\n';
903 if (!
cycle() && _type ==
"directed") {
905 std::reverse(top_sort.begin(), top_sort.end());
907 std::unordered_map<T, double> dist;
908 for (
auto& x : _elements) {
909 dist[x] = std::numeric_limits<int64_t>::max();
912 while (!top_sort.empty()) {
913 auto current = top_sort.back();
915 if (dist[current] != std::numeric_limits<int64_t>::max()) {
916 for (std::pair<T, double>& x : adj[current]) {
917 if (dist[x.first] > dist[current] + x.second) {
918 dist[x.first] = dist[current] + x.second;
919 top_sort.push_back(x.first);
924 return (dist[end] != std::numeric_limits<int64_t>::max()) ? dist[end] : -1;
926 std::unordered_map<T, double> dist;
927 for (
auto& x : _elements) {
928 dist[x] = std::numeric_limits<int64_t>::max();
930 std::priority_queue<std::pair<double, T>, std::vector<std::pair<double, T>>,
931 std::greater<std::pair<double, T>>>
933 pq.push(std::make_pair(0, start));
935 while (!pq.empty()) {
936 T currentNode = pq.top().second;
937 double currentDist = pq.top().first;
939 for (std::pair<T, double>& edge : adj[currentNode]) {
940 if (currentDist + edge.second < dist[edge.first]) {
941 dist[edge.first] = currentDist + edge.second;
942 pq.push(std::make_pair(dist[edge.first], edge.first));
946 return (dist[end] != std::numeric_limits<int64_t>::max()) ? dist[end] : -1;
954 if (this->
empty() || _elements.find(start) == _elements.end()) {
958 std::unordered_map<T, bool> visited;
960 visited[start] =
true;
962 int64_t
size = s.size();
963 for (int64_t i = 0; i <
size; i++) {
965 path.push_back(current);
967 for (std::pair<T, double>& x : adj[current]) {
968 if (visited.find(x.first) == visited.end()) {
970 visited[x.first] =
true;
980 if (this->
empty() || _elements.find(start) == _elements.end()) {
984 std::unordered_map<T, bool> visited;
986 visited[start] =
true;
988 int64_t
size = q.size();
989 for (int64_t i = 0; i <
size; i++) {
990 T current = q.front();
991 path.push_back(current);
993 for (std::pair<T, double>& x : adj[current]) {
994 if (visited.find(x.first) == visited.end()) {
996 visited[x.first] =
true;
1005 auto explore = [&](std::unordered_map<T, bool>& visited, T element) ->
void {
1008 visited[element] =
true;
1009 while (!s.empty()) {
1010 T current = s.top();
1012 for (std::pair<T, double>& x : adj[current]) {
1013 if (visited.find(x.first) == visited.end()) {
1015 visited[x.first] =
true;
1020 size_t n = _elements.size();
1022 std::unordered_map<T, bool> visited;
1023 for (T x : _elements) {
1024 if (visited.find(x) == visited.end()) {
1025 explore(visited, x);
1033 std::unordered_map<T, int> indeg;
1037 for (T x : _elements) {
1038 for (std::pair<T, double>& y : adj[x]) {
1043 for (T x : _elements) {
1044 if (indeg[x] == 0) {
1049 while (!q.empty()) {
1050 T current = q.front();
1053 for (std::pair<T, double>& x : adj[current]) {
1054 if (--indeg[x.first] == 0) {
1059 return visited == 0;
1063 std::vector<T> top_sort;
1064 std::unordered_map<T, bool> visited;
1065 std::unordered_map<T, int64_t> indeg;
1066 for (T x : _elements) {
1067 for (std::pair<T, double>& y : adj[x]) {
1073 for (T x : _elements) {
1074 if (indeg[x] == 0) {
1080 while (!q.empty()) {
1081 T current = q.front();
1083 top_sort.push_back(current);
1084 for (std::pair<T, double>& x : adj[current]) {
1085 if (visited.find(x.first) == visited.end()) {
1086 if (--indeg[x.first] == 0) {
1088 visited[x.first] =
true;
1098 std::priority_queue<std::pair<T, int64_t>, std::vector<std::pair<T, int64_t>>,
1099 std::greater<std::pair<T, int64_t>>>
1101 std::unordered_map<T, bool> visited;
1103 q.push(std::make_pair(0, _temp));
1104 while (!q.empty()) {
1105 std::pair<T, int64_t> current = q.top();
1107 _temp = current.first;
1108 if (visited.find(_temp) != visited.end()) {
1111 cost += current.second;
1112 visited[_temp] =
true;
1113 for (std::pair<T, double>& x : adj[current.first]) {
1114 if (visited.find(x.first) == visited.end()) {
1123 std::unordered_map<T, int> color;
1124 std::queue<std::pair<T, int>> q;
1126 for (T x : _elements) {
1127 if (color.find(x) == color.end()) {
1130 while (!q.empty()) {
1131 std::pair<T, int> current = q.front();
1133 T v = current.first;
1134 int col = current.second;
1135 for (std::pair<T, double>& x : adj[v]) {
1136 if (color.find(x.first) != color.end() && color[x.first] == col) {
1139 if (color.find(x.first) == color.end()) {
1140 color[x.first] = (col) ? 0 : 1;
1141 q.push({x.first, color[x.first]});
1152 std::vector<std::vector<T>> bridges;
1153 std::unordered_map<T, bool> visited;
1154 std::unordered_map<T, int64_t> in, out;
1155 for (T x : _elements) {
1159 dfs_bridge(start, -1, timer, visited, in, out, bridges);
1164 if (this->
size() == 0) {
1168 std::unordered_map<T, bool> visited;
1171 for (
const T& x : _elements) {
1172 if (visited.find(x) == visited.end()) {
1173 dfs_scc(x, visited, s);
1177 std::unordered_map<T, std::vector<T>> new_adj;
1178 for (
const T& x : _elements) {
1179 for (
const auto& neigh : adj[x]) {
1180 new_adj[neigh.first].push_back(x);
1187 auto dfs_new = [&](T start) ->
void {
1190 visited[start] =
true;
1191 while (!_s.empty()) {
1192 T current = _s.top();
1194 for (
auto& x : new_adj[current]) {
1195 if (visited.find(x) == visited.end()) {
1203 while (!s.empty()) {
1204 T current = s.top();
1206 if (visited.find(current) == visited.end()) {
1216 std::unordered_map<T, bool> visited;
1219 for (
auto& ele : adj) {
1220 if (adj[ele.first].size() != 0) {
1231 visited[start] =
true;
1232 while (!s.empty()) {
1233 T current = s.top();
1235 for (std::pair<T, double>& x : adj[current]) {
1236 if (visited.find(x.first) == visited.end()) {
1237 visited[x.first] =
true;
1243 for (T x : _elements) {
1244 if (visited.find(x) == visited.end() && adj[x].size() > 0) {
1257 for (
auto& el : adj) {
1258 if (adj[el.first].size() & 1) {
1267 return (odd) ? 1 : 2;
1271 std::unordered_map<T, double> dist;
1274 for (
auto it : adj) {
1275 dist[it.first] = std::numeric_limits<double>::infinity();
1283 for (
int i = 0; i < v - 1; i++) {
1284 for (
const auto j : adj) {
1285 for (
const auto edge : adj[j.first]) {
1286 if (dist[j.first] + edge.second < dist[edge.first]) {
1287 dist[edge.first] = dist[j.first] + edge.second;
1296 for (
int i = 0; i < v - 1; i++) {
1297 for (
const auto j : adj) {
1298 for (
const auto edge : adj[j.first]) {
1299 if (dist[j.first] + edge.second < dist[edge.first]) {
1300 dist[edge.first] = -std::numeric_limits<double>::infinity();
1310#ifdef ENABLE_GRAPH_VISUALIZATION
1313 if (_type ==
"directed") {
1314 if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
1315 for (
auto& [element, neighbors] : adj) {
1316 for (std::pair<T, double>& x : neighbors) {
1317 if (x.first == element) {
1324 s += std::to_string(x.second);
1330 for (
auto& [element, neighbors] : adj) {
1331 for (std::pair<T, double>& x : neighbors) {
1332 if (x.first == element) {
1335 s += std::to_string(element);
1337 s += std::to_string(x.first);
1339 s += std::to_string(x.second);
1346 if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
1347 for (
auto& [element, neighbors] : adj) {
1348 for (std::pair<T, double>& x : neighbors) {
1349 if (x.first == element) {
1356 s += std::to_string(x.second);
1362 for (
auto& [element, neighbors] : adj) {
1363 for (std::pair<T, double>& x : neighbors) {
1364 if (x.first == element) {
1367 s += std::to_string(element);
1369 s += std::to_string(x.first);
1371 s += std::to_string(x.second);
1378 if (_type ==
"directed") {
1379 digraph_visualization::visualize(s);
1381 graph_visualization::visualize(s);
int64_t scc()
scc(strongly connected components) function.
Definition graph.h:497
friend std::ostream & operator<<(std::ostream &out, graph< T > &g)
operator << for the graph class.
Definition graph.h:217
bool bipartite()
bipartite function.
Definition graph.h:420
void add_edge(T u, T v)
add_edge function
Definition graph.h:89
std::vector< T > bfs(T start)
bfs function
Definition graph.h:301
std::vector< std::vector< T > > bridge(T start)
bridge function.
Definition graph.h:448
bool has_edge(T start, T end)
has_edge function.
Definition graph.h:107
std::vector< T > dfs(T start)
dfs function
Definition graph.h:278
std::vector< T > topological_sort()
topological_sort function.
Definition graph.h:385
bool cycle()
cycle function.
Definition graph.h:355
void visualize()
visualize function.
void clear()
clear function Clearing the entire graph.
Definition graph.h:123
~graph()
Destroy the graph object.
Definition graph.h:82
bool connected()
connected function.
Definition graph.h:461
graph(std::string _type, std::vector< std::pair< T, std::vector< T > > > _adj={})
Constructor for the unweighted graph.
Definition graph.h:39
size_t size()
size function
Definition graph.h:274
int64_t connected_components()
connected_components function.
Definition graph.h:327
graph(const graph &g)
Construct a new graph object.
Definition graph.h:64
int eulerian()
eulerian function.
Definition graph.h:549
graph & operator=(const graph &g)
operator = for the graph class
Definition graph.h:72
bool empty()
empty function Checks if a graph is empty.
Definition graph.h:132
int eulerian()
eulerian function.
Definition graph.h:1251
int64_t scc()
scc(strongly connected components) function.
Definition graph.h:1163
double shortest_path(T start, T end)
shortest_path function.
Definition graph.h:893
int64_t connected_components()
connected_components function.
Definition graph.h:1004
~weighted_graph()
Destroy the weighted graph object.
Definition graph.h:672
bool bipartite()
bipartite function.
Definition graph.h:1122
std::vector< std::vector< T > > bridge(T start)
bridge function.
Definition graph.h:1150
bool has_edge(T start, T end)
has_edge function.
Definition graph.h:697
weighted_graph(const weighted_graph &g)
Copy constructor for weighted graph class.
Definition graph.h:653
bool cycle()
cycle function.
Definition graph.h:1032
std::vector< T > topological_sort()
topological sort function.
Definition graph.h:1062
std::vector< T > bfs(T start)
bfs function.
Definition graph.h:978
bool empty()
empty function.
Definition graph.h:721
bool connected()
connected function.
Definition graph.h:1215
void visualize()
visualize function.
std::unordered_map< T, double > bellman_ford(T start)
find SSSP and identify negative cycles.
Definition graph.h:1270
std::vector< T > dfs(T start)
dfs function.
Definition graph.h:951
void add_edge(T u, T v, int64_t w)
add_edge function.
Definition graph.h:680
size_t size()
size function.
Definition graph.h:889
int max_flow(T start, T end)
maximum flow function
weighted_graph(std::string _type, std::vector< std::pair< std::pair< T, T >, int64_t > > _adj={})
Constructor for weighted graph.
Definition graph.h:631
void clear()
clear function. Clearing the entire graph.
Definition graph.h:713
weighted_graph & operator=(const weighted_graph &g)
operator = for weighted graph class
Definition graph.h:661
int64_t prim(T start)
prim function.
Definition graph.h:1097
friend std::ostream & operator<<(std::ostream &out, weighted_graph< T > &g)
<< operator for the weighted graph class.
Definition graph.h:833