AlgoPlus  v0.1.0
graph.h
1 #ifndef GRAPH_H
2 #define GRAPH_H
3 
4 #ifdef GRAPH_VISUALIZATION_H
5 #include "../../visualization/graph_visual/graph_visualization.h"
6 #endif
7 
8 #ifdef __cplusplus
9 #include <algorithm>
10 #include <climits>
11 #include <iostream>
12 #include <limits>
13 #include <queue>
14 #include <stack>
15 #include <string>
16 #include <type_traits>
17 #include <unordered_map>
18 #include <unordered_set>
19 #include <utility>
20 #endif
21 
27 template <typename T> class graph {
28 public:
35  graph(std::string _type,
36  std::vector<std::pair<T, std::vector<T>>> _adj = {}) {
37  try {
38  if (_type == "directed" || _type == "undirected") {
39  this->_type = _type;
40  } else {
41  throw std::invalid_argument("Can't recognize the type of graph");
42  }
43  if (!_adj.empty()) {
44  for (size_t i = 0; i < _adj.size(); i++) {
45  for (T &neigh : _adj[i].second) {
46  this->add_edge(_adj[i].first, neigh);
47  }
48  }
49  }
50  } catch (std::invalid_argument &e) {
51  std::cerr << e.what() << '\n';
52  return;
53  }
54  }
55 
61  graph(const graph &g) : adj(g.adj), _elements(g._elements), _type(g._type) {
62  }
63 
70  graph &operator=(const graph &g) {
71  adj = g.adj;
72  _elements = g._elements;
73  _type = g._type;
74  return *this;
75  }
76 
80  ~graph() { adj.clear(); }
81 
87  void add_edge(T u, T v) {
88  if (_type == "undirected") {
89  adj[u].push_back(v);
90  adj[v].push_back(u);
91  } else {
92  adj[u].push_back(v);
93  }
94  _elements.insert(u);
95  _elements.insert(v);
96  }
97 
105  bool has_edge(T start, T end) {
106  if (_elements.find(start) == _elements.end()) {
107  return false;
108  }
109  for (T &x : adj[start]) {
110  if (x == end) {
111  return true;
112  }
113  }
114  return false;
115  }
116 
121  void clear() {
122  _elements.clear();
123  adj.clear();
124  }
125 
130  bool empty() { return _elements.empty(); }
131 
136  size_t size();
137 
143  std::vector<T> dfs(T start);
144 
150  std::vector<T> bfs(T start);
151 
156  int64_t connected_components();
157 
162  bool cycle();
163 
168  std::vector<T> topological_sort();
169 
174  bool bipartite();
175 
182  std::vector<std::vector<T>> bridge(T start);
183 
188  int64_t scc();
189 
194  bool connected();
195 
202  int eulerian();
203 
208  void visualize();
209 
214  friend std::ostream &operator<<(std::ostream &out, graph<T> &g) {
215  out << '{';
216 
217  std::vector<T> elements = g.topological_sort();
218  for (T &x : elements) {
219  out << x << ' ';
220  }
221  out << '}' << '\n';
222  return out;
223  }
224 
225 private:
231  std::unordered_map<T, std::vector<T>> adj;
232  std::unordered_set<T> _elements;
233  std::string _type;
234 
238  void dfs_bridge(T start, T parent, int64_t &time,
239  std::unordered_map<T, bool> &visited,
240  std::unordered_map<T, int64_t> &in,
241  std::unordered_map<T, int64_t> &out,
242  std::vector<std::vector<T>> &bridges) {
243  visited[start] = true;
244  in[start] = out[start] = time++;
245  for (T &x : adj[start]) {
246  if (x != parent) {
247  if (visited.find(x) == visited.end()) {
248  dfs_bridge(x, start, time, visited, in, out, bridges);
249  if (out[x] > in[start]) {
250  bridges.push_back({x, start});
251  }
252  }
253  out[start] = std::min(out[start], out[x]);
254  }
255  }
256  }
257 };
258 
259 template <typename T> size_t graph<T>::size() { return _elements.size(); }
260 
261 template <typename T> std::vector<T> graph<T>::dfs(T start) {
262  std::vector<T> path;
263  if (this->empty() || _elements.find(start) == _elements.end()) {
264  return path;
265  }
266  std::stack<T> s;
267  std::unordered_map<T, bool> visited;
268  s.push(start);
269  visited[start] = true;
270  while (!s.empty()) {
271  T current = s.top();
272  path.push_back(current);
273  s.pop();
274  for (T &x : adj[current]) {
275  if (visited.find(x) == visited.end()) {
276  s.push(x);
277  visited[x] = true;
278  }
279  }
280  }
281  return path;
282 }
283 
284 template <typename T> std::vector<T> graph<T>::bfs(T start) {
285  std::vector<T> path;
286  if (this->empty() || _elements.find(start) == _elements.end()) {
287  return path;
288  }
289  std::queue<T> q;
290  std::unordered_map<T, bool> visited;
291  q.push(start);
292  visited[start] = true;
293  while (!q.empty()) {
294  int64_t size = q.size();
295  for (int64_t i = 0; i < size; i++) {
296  T current = q.front();
297  path.push_back(current);
298  q.pop();
299  for (T &x : adj[current]) {
300  if (visited.find(x) == visited.end()) {
301  q.push(x);
302  visited[x] = true;
303  }
304  }
305  }
306  }
307  return path;
308 }
309 
310 template <typename T> int64_t graph<T>::connected_components() {
311  auto explore = [&](std::unordered_map<T, bool> &visited, T element) -> void {
312  std::queue<T> q;
313  q.push(element);
314  visited[element] = true;
315  while (!q.empty()) {
316  T current = q.front();
317  q.pop();
318  for (T &x : adj[current]) {
319  if (visited.find(x) == visited.end()) {
320  q.push(x);
321  visited[x] = true;
322  }
323  }
324  }
325  };
326  size_t n = _elements.size();
327  int64_t cc = 0;
328  std::unordered_map<T, bool> visited;
329  for (T x : _elements) {
330  if (visited.find(x) == visited.end()) {
331  explore(visited, x);
332  cc++;
333  }
334  }
335  return cc;
336 }
337 
338 template <typename T> bool graph<T>::cycle() {
339  std::unordered_map<T, int> indeg;
340  std::queue<T> q;
341  size_t visited = 0;
342 
343  for (T x : _elements) {
344  for (T &y : adj[x]) {
345  indeg[y]++;
346  }
347  }
348 
349  for (T x : _elements) {
350  if (indeg[x] == 0) {
351  q.push(x);
352  }
353  }
354 
355  while (!q.empty()) {
356  T current = q.front();
357  q.pop();
358  visited++;
359  for (T &x : adj[current]) {
360  if (--indeg[x] == 0) {
361  q.push(x);
362  }
363  }
364  }
365  return visited == 0;
366 }
367 
368 template <typename T> std::vector<T> graph<T>::topological_sort() {
369  std::vector<T> top_sort;
370  std::unordered_map<T, bool> visited;
371  std::unordered_map<T, int64_t> indeg;
372  for (T x : _elements) {
373  for (T &y : adj[x]) {
374  indeg[y]++;
375  }
376  }
377 
378  std::queue<T> q;
379  for (T x : _elements) {
380  if (indeg[x] == 0) {
381  q.push(x);
382  visited[x] = true;
383  }
384  }
385 
386  while (!q.empty()) {
387  T current = q.front();
388  q.pop();
389  top_sort.push_back(current);
390  for (T &x : adj[current]) {
391  if (visited.find(x) == visited.end()) {
392  if (--indeg[x] == 0) {
393  q.push(x);
394  visited[x] = true;
395  }
396  }
397  }
398  }
399 
400  return top_sort;
401 }
402 
403 template <typename T> bool graph<T>::bipartite() {
404  std::unordered_map<T, int> color;
405  std::queue<std::pair<T, int>> q;
406 
407  for (T x : _elements) {
408  if (color.find(x) == color.end()) {
409  q.push({x, 0});
410  color[x] = 0;
411  while (!q.empty()) {
412  std::pair<T, int> current = q.front();
413  q.pop();
414  T v = current.first;
415  int col = current.second;
416  for (T &x : adj[v]) {
417  if (color.find(x) != color.end() && color[x] == col) {
418  return false;
419  }
420  if (color.find(x) == color.end()) {
421  color[x] = (col) ? 0 : 1;
422  q.push({x, color[x]});
423  }
424  }
425  }
426  }
427  }
428  return true;
429 }
430 
431 template <typename T> std::vector<std::vector<T>> graph<T>::bridge(T start) {
432  int64_t timer = 0;
433  std::vector<std::vector<T>> bridges;
434  std::unordered_map<T, bool> visited;
435  std::unordered_map<T, int64_t> in, out;
436  for (T x : _elements) {
437  in[x] = 0;
438  out[x] = 0;
439  }
440  dfs_bridge(start, -1, timer, visited, in, out, bridges);
441  return bridges;
442 }
443 
444 template <typename T> bool graph<T>::connected() {
445  std::unordered_map<T, bool> visited;
446  bool check = 0;
447  T start;
448  for (auto &ele : adj) {
449  if (adj[ele.first].size() != 0) {
450  start = ele.first;
451  check = 1;
452  break;
453  }
454  }
455  if (!check) {
456  return false;
457  }
458  std::stack<T> s;
459  s.push(start);
460  visited[start] = true;
461  while (!s.empty()) {
462  T current = s.top();
463  s.pop();
464  for (T &x : adj[current]) {
465  if (visited.find(x) == visited.end()) {
466  visited[x] = true;
467  s.push(x);
468  }
469  }
470  }
471 
472  for (T x : _elements) {
473  if (visited.find(x) == visited.end() && adj[x].size() > 0) {
474  return false;
475  }
476  }
477  return true;
478 }
479 
480 template <typename T> int graph<T>::eulerian() {
481  if (this->connected() == false) {
482  return false;
483  }
484 
485  int64_t odd = 0;
486  for (auto &el : adj) {
487  if (adj[el.first].size() & 1) {
488  odd++;
489  }
490  }
491 
492  if (odd > 2) {
493  return false;
494  }
495  return (odd) ? 1 : 2;
496 }
497 
498 #ifdef GRAPH_VISUALIZATION_H
499 template <typename T> void graph<T>::visualize() {
500  std::string s;
501  if (_type == "directed") {
502  if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
503  for (auto &[element, neighbors] : adj) {
504  for (T &x : neighbors) {
505  s += element;
506  s += "->";
507  s += x;
508  s += '\n';
509  }
510  }
511  } else {
512  for (auto &[element, neighbors] : adj) {
513  for (T &x : neighbors) {
514  s += std::to_string(element);
515  s += "->";
516  s += std::to_string(x);
517  s += '\n';
518  }
519  }
520  }
521  } else {
522  if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
523  for (auto &[element, neighbors] : adj) {
524  for (T &x : neighbors) {
525  s += element;
526  s += "--";
527  s += x;
528  s += '\n';
529  }
530  }
531  } else {
532  for (auto &[element, neighbors] : adj) {
533  for (T &x : neighbors) {
534  s += std::to_string(element);
535  s += "--";
536  s += std::to_string(x);
537  s += '\n';
538  }
539  }
540  }
541  }
542  s += '\n';
543  if (_type == "directed") {
544  digraph_visualization::visualize(s);
545  } else {
546  graph_visualization::visualize(s);
547  }
548 }
549 #endif
550 
554 template <typename T> class weighted_graph {
555 public:
562  weighted_graph(std::string _type,
563  std::vector<std::pair<std::pair<T, T>, int64_t>> _adj = {}) {
564  try {
565  if (_type == "directed" || _type == "undirected") {
566  this->_type = _type;
567  } else {
568  throw std::invalid_argument("Can't recognize the type of graph");
569  }
570  if (!_adj.empty()) {
571  for (size_t i = 0; i < _adj.size(); i++) {
572  this->add_edge(_adj[i].first.first, _adj[i].first.second,
573  _adj[i].second);
574  }
575  }
576  } catch (std::invalid_argument &e) {
577  std::cerr << e.what() << '\n';
578  return;
579  }
580  }
581 
586  explicit weighted_graph(const weighted_graph &g) : adj(g.adj), _elements(g._elements), _type(g._type) {
587 
588 
589 
590  }
591 
598  adj = g.adj;
599  _elements = g._elements;
600  _type = g._type;
601  return *this;
602  }
603 
608  ~weighted_graph() { adj.clear(); }
609 
616  void add_edge(T u, T v, int64_t w) {
617  if (_type == "undirected") {
618  adj[u].push_back(std::make_pair(v, w));
619  adj[v].push_back(std::make_pair(u, w));
620  } else if (_type == "directed") {
621  adj[u].push_back(std::make_pair(v, w));
622  }
623  _elements.insert(u);
624  _elements.insert(v);
625  }
626 
633  bool has_edge(T start, T end) {
634  if (_elements.find(start) == _elements.end()) {
635  return false;
636  }
637  for (std::pair<T, double> &x : adj[start]) {
638  if (x.first == end) {
639  return true;
640  }
641  }
642  return false;
643  }
644 
649  void clear() {
650  _elements.clear();
651  adj.clear();
652  }
657  bool empty() { return _elements.empty(); }
658 
663  size_t size();
664 
670  std::vector<T> dfs(T start);
671 
677  std::vector<T> bfs(T start);
678 
685  double shortest_path(T start, T end);
686 
691  int64_t connected_components();
692 
697  bool cycle();
698 
703  std::vector<T> topological_sort();
704 
710  int64_t prim(T start);
711 
716  bool bipartite();
717 
723  std::vector<std::vector<T>> bridge(T start);
724 
729  int64_t scc();
730 
735  bool connected();
736 
743  int eulerian();
744 
749  std::unordered_map<T, double> bellman_ford(T start);
750 
755  void visualize();
756 
761  friend std::ostream &operator<<(std::ostream &out, weighted_graph<T> &g) {
762  out << '{';
763  std::vector<T> elements = g.topological_sort();
764  for (T &x : elements) {
765  out << x << ' ';
766  }
767  out << '}' << '\n';
768  return out;
769  }
770 
771 private:
777  std::unordered_map<T, std::vector<std::pair<T, double>>> adj;
778  std::string _type;
779  std::unordered_set<T> _elements;
780 
784  void dfs_bridge(T start, T parent, int64_t &time,
785  std::unordered_map<T, bool> &visited,
786  std::unordered_map<T, int64_t> &in,
787  std::unordered_map<T, int64_t> &out,
788  std::vector<std::vector<T>> &bridges) {
789  visited[start] = true;
790  in[start] = out[start] = time++;
791  for (std::pair<T, double> &x : adj[start]) {
792  if (x.first != parent) {
793  if (visited.find(x.first) == visited.end()) {
794  dfs_bridge(x.first, start, time, visited, in, out, bridges);
795  if (out[x.first] > in[start]) {
796  bridges.push_back({x.first, start});
797  }
798  }
799  out[start] = std::min(out[start], out[x.first]);
800  }
801  }
802  }
803 };
804 
805 template <typename T> size_t weighted_graph<T>::size() {
806  return _elements.size();
807 }
808 
809 template <typename T> double weighted_graph<T>::shortest_path(T start, T end) {
810  if (_elements.find(start) == _elements.end()) {
811  std::cout << "Element: " << start << " is not found in the Graph" << '\n';
812  return -1;
813  }
814  if (_elements.find(end) == _elements.end()) {
815  std::cout << "Element: " << end << " is not found in the Graph" << '\n';
816  return -1;
817  }
818 
819  if (!cycle() && _type == "directed") {
820  std::vector<T> top_sort = topological_sort();
821  std::reverse(top_sort.begin(), top_sort.end());
822  std::stack<T> s;
823  std::unordered_map<T, double> dist;
824  for (auto &x : _elements) {
825  dist[x] = std::numeric_limits<int64_t>::max();
826  }
827  dist[start] = 0;
828  while (!top_sort.empty()) {
829  auto current = top_sort.back();
830  top_sort.pop_back();
831  if (dist[current] != std::numeric_limits<int64_t>::max()) {
832  for (std::pair<T, double> &x : adj[current]) {
833  if (dist[x.first] > dist[current] + x.second) {
834  dist[x.first] = dist[current] + x.second;
835  top_sort.push_back(x.first);
836  }
837  }
838  }
839  }
840  return (dist[end] != std::numeric_limits<int64_t>::max()) ? dist[end] : -1;
841  } else {
842  std::unordered_map<T, double> dist;
843  for (auto &x : _elements) {
844  dist[x] = std::numeric_limits<int64_t>::max();
845  }
846  std::priority_queue<std::pair<double, T>,
847  std::vector<std::pair<double, T>>,
848  std::greater<std::pair<double, T>>>
849  pq;
850  pq.push(std::make_pair(0, start));
851  dist[start] = 0;
852  while (!pq.empty()) {
853  T currentNode = pq.top().second;
854  double currentDist = pq.top().first;
855  pq.pop();
856  for (std::pair<T, double> &edge : adj[currentNode]) {
857  if (currentDist + edge.second < dist[edge.first]) {
858  dist[edge.first] = currentDist + edge.second;
859  pq.push(std::make_pair(dist[edge.first], edge.first));
860  }
861  }
862  }
863  return (dist[end] != std::numeric_limits<int64_t>::max()) ? dist[end] : -1;
864  }
865  return -1;
866 }
867 
868 template <typename T> std::vector<T> weighted_graph<T>::dfs(T start) {
869 
870  std::vector<T> path;
871  if (this->empty() || _elements.find(start) == _elements.end()) {
872  return path;
873  }
874  std::stack<T> s;
875  std::unordered_map<T, bool> visited;
876  s.push(start);
877  visited[start] = true;
878  while (!s.empty()) {
879  int64_t size = s.size();
880  for (int64_t i = 0; i < size; i++) {
881  T current = s.top();
882  path.push_back(current);
883  s.pop();
884  for (std::pair<T, double> &x : adj[current]) {
885  if (visited.find(x.first) == visited.end()) {
886  s.push(x.first);
887  visited[x.first] = true;
888  }
889  }
890  }
891  }
892  return path;
893 }
894 
895 template <typename T> std::vector<T> weighted_graph<T>::bfs(T start) {
896  std::vector<T> path;
897  if (this->empty() || _elements.find(start) == _elements.end()) {
898  return path;
899  }
900  std::queue<T> q;
901  std::unordered_map<T, bool> visited;
902  q.push(start);
903  visited[start] = true;
904  while (!q.empty()) {
905  int64_t size = q.size();
906  for (int64_t i = 0; i < size; i++) {
907  T current = q.front();
908  path.push_back(current);
909  q.pop();
910  for (std::pair<T, double> &x : adj[current]) {
911  if (visited.find(x.first) == visited.end()) {
912  q.push(x.first);
913  visited[x.first] = true;
914  }
915  }
916  }
917  }
918  return path;
919 }
920 
921 template <typename T> int64_t weighted_graph<T>::connected_components() {
922  auto explore = [&](std::unordered_map<T, bool> &visited, T element) -> void {
923  std::stack<T> s;
924  s.push(element);
925  visited[element] = true;
926  while (!s.empty()) {
927  T current = s.top();
928  s.pop();
929  for (std::pair<T, double> &x : adj[current]) {
930  if (visited.find(x.first) == visited.end()) {
931  s.push(x.first);
932  visited[x.first] = true;
933  }
934  }
935  }
936  };
937  size_t n = _elements.size();
938  int64_t cc = 0;
939  std::unordered_map<T, bool> visited;
940  for (T x : _elements) {
941  if (visited.find(x) == visited.end()) {
942  explore(visited, x);
943  cc++;
944  }
945  }
946  return cc;
947 }
948 
949 template <typename T> bool weighted_graph<T>::cycle() {
950  std::unordered_map<T, int> indeg;
951  std::queue<T> q;
952  size_t visited = 0;
953 
954  for (T x : _elements) {
955  for (std::pair<T, double> &y : adj[x]) {
956  indeg[y.first]++;
957  }
958  }
959 
960  for (T x : _elements) {
961  if (indeg[x] == 0) {
962  q.push(x);
963  }
964  }
965 
966  while (!q.empty()) {
967  T current = q.front();
968  q.pop();
969  visited++;
970  for (std::pair<T, double> &x : adj[current]) {
971  if (--indeg[x.first] == 0) {
972  q.push(x.first);
973  }
974  }
975  }
976  return visited == 0;
977 }
978 
979 template <typename T> std::vector<T> weighted_graph<T>::topological_sort() {
980  std::vector<T> top_sort;
981  std::unordered_map<T, bool> visited;
982  std::unordered_map<T, int64_t> indeg;
983  for (T x : _elements) {
984  for (std::pair<T, double> &y : adj[x]) {
985  indeg[y.first]++;
986  }
987  }
988 
989  std::queue<T> q;
990  for (T x : _elements) {
991  if (indeg[x] == 0) {
992  q.push(x);
993  visited[x] = true;
994  }
995  }
996 
997  while (!q.empty()) {
998  T current = q.front();
999  q.pop();
1000  top_sort.push_back(current);
1001  for (std::pair<T, double> &x : adj[current]) {
1002  if (visited.find(x.first) == visited.end()) {
1003  if (--indeg[x.first] == 0) {
1004  q.push(x.first);
1005  visited[x.first] = true;
1006  }
1007  }
1008  }
1009  }
1010 
1011  return top_sort;
1012 }
1013 
1014 template <typename T> int64_t weighted_graph<T>::prim(T _temp) {
1015  std::priority_queue<std::pair<T, int64_t>, std::vector<std::pair<T, int64_t>>,
1016  std::greater<std::pair<T, int64_t>>>
1017  q;
1018  std::unordered_map<T, bool> visited;
1019  int64_t cost = 0;
1020  q.push(std::make_pair(0, _temp));
1021  while (!q.empty()) {
1022  std::pair<T, int64_t> current = q.top();
1023  q.pop();
1024  _temp = current.first;
1025  if (visited.find(_temp) != visited.end()) {
1026  continue;
1027  }
1028  cost += current.second;
1029  visited[_temp] = true;
1030  for (std::pair<T, double> &x : adj[current.first]) {
1031  if (visited.find(x.first) == visited.end()) {
1032  q.push(x);
1033  }
1034  }
1035  }
1036  return cost;
1037 }
1038 
1039 template <typename T> bool weighted_graph<T>::bipartite() {
1040  std::unordered_map<T, int> color;
1041  std::queue<std::pair<T, int>> q;
1042 
1043  for (T x : _elements) {
1044  if (color.find(x) == color.end()) {
1045  q.push({x, 0});
1046  color[x] = 0;
1047  while (!q.empty()) {
1048  std::pair<T, int> current = q.front();
1049  q.pop();
1050  T v = current.first;
1051  int col = current.second;
1052  for (std::pair<T, double> &x : adj[v]) {
1053  if (color.find(x.first) != color.end() && color[x.first] == col) {
1054  return false;
1055  }
1056  if (color.find(x.first) == color.end()) {
1057  color[x.first] = (col) ? 0 : 1;
1058  q.push({x.first, color[x.first]});
1059  }
1060  }
1061  }
1062  }
1063  }
1064  return true;
1065 }
1066 
1067 template <typename T>
1068 std::vector<std::vector<T>> weighted_graph<T>::bridge(T start) {
1069  int64_t timer = 0;
1070  std::vector<std::vector<T>> bridges;
1071  std::unordered_map<T, bool> visited;
1072  std::unordered_map<T, int64_t> in, out;
1073  for (T x : _elements) {
1074  in[x] = 0;
1075  out[x] = 0;
1076  }
1077  dfs_bridge(start, -1, timer, visited, in, out, bridges);
1078  return bridges;
1079 }
1080 
1081 template <typename T> bool weighted_graph<T>::connected() {
1082  std::unordered_map<T, bool> visited;
1083  bool check = 0;
1084  T start;
1085  for (auto &ele : adj) {
1086  if (adj[ele.first].size() != 0) {
1087  start = ele.first;
1088  check = 1;
1089  break;
1090  }
1091  }
1092  if (!check) {
1093  return false;
1094  }
1095  std::stack<T> s;
1096  s.push(start);
1097  visited[start] = true;
1098  while (!s.empty()) {
1099  T current = s.top();
1100  s.pop();
1101  for (std::pair<T, double> &x : adj[current]) {
1102  if (visited.find(x.first) == visited.end()) {
1103  visited[x.first] = true;
1104  s.push(x.first);
1105  }
1106  }
1107  }
1108 
1109  for (T x : _elements) {
1110  if (visited.find(x) == visited.end() && adj[x].size() > 0) {
1111  return false;
1112  }
1113  }
1114  return true;
1115 }
1116 
1117 template <typename T> int weighted_graph<T>::eulerian() {
1118  if (this->connected() == false) {
1119  return false;
1120  }
1121 
1122  int odd = 0;
1123  for (auto &el : adj) {
1124  if (adj[el.first].size() & 1) {
1125  odd++;
1126  }
1127  }
1128 
1129  if (odd > 2) {
1130  return 0;
1131  }
1132 
1133  return (odd) ? 1 : 2;
1134 }
1135 
1136 template <typename T>
1137 std::unordered_map<T, double> weighted_graph<T>::bellman_ford(T start) {
1138  std::unordered_map<T, double> dist;
1139  // Initialize the distance to all nodes to be infinity
1140  // except for the starting node which is zero.
1141  for (auto it : adj)
1142  dist[it.first] = std::numeric_limits<double>::infinity();
1143  dist[start] = 0;
1144 
1145  // Get number of vertices present in the graph
1146  int v = adj.size();
1147 
1148  // For each vertex, apply relaxation for all the edges
1149  for (int i = 0; i < v - 1; i++)
1150  for (const auto j : adj)
1151  for (const auto edge : adj[j.first])
1152  if (dist[j.first] + edge.second < dist[edge.first])
1153  dist[edge.first] = dist[j.first] + edge.second;
1154 
1155  // Run algorithm a second time to detect which nodes are part
1156  // of a negative cycle. A negative cycle has occurred if we
1157  // can find a better path beyond the optimal solution.
1158  for (int i = 0; i < v - 1; i++)
1159  for (const auto j : adj)
1160  for (const auto edge : adj[j.first])
1161  if (dist[j.first] + edge.second < dist[edge.first])
1162  dist[edge.first] = -std::numeric_limits<double>::infinity();
1163 
1164  // Return the array containing the shortest distance to every node
1165  return dist;
1166 }
1167 
1168 #ifdef GRAPH_VISUALIZATION_H
1169 template <typename T> void weighted_graph<T>::visualize() {
1170  std::string s;
1171  if (_type == "directed") {
1172  if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
1173  for (auto &[element, neighbors] : adj) {
1174  for (std::pair<T, double> &x : neighbors) {
1175  if (x.first == element) {
1176  continue;
1177  }
1178  s += element;
1179  s += "->";
1180  s += x.first;
1181  s += "[label=";
1182  s += std::to_string(x.second);
1183  s += "]";
1184  s += '\n';
1185  }
1186  }
1187  } else {
1188  for (auto &[element, neighbors] : adj) {
1189  for (std::pair<T, double> &x : neighbors) {
1190  if (x.first == element) {
1191  continue;
1192  }
1193  s += std::to_string(element);
1194  s += "->";
1195  s += std::to_string(x.first);
1196  s += "[label=";
1197  s += std::to_string(x.second);
1198  s += "]";
1199  s += '\n';
1200  }
1201  }
1202  }
1203  } else {
1204  if (std::is_same_v<T, char> || std::is_same_v<T, std::string>) {
1205  for (auto &[element, neighbors] : adj) {
1206  for (std::pair<T, double> &x : neighbors) {
1207  if (x.first == element) {
1208  continue;
1209  }
1210  s += element;
1211  s += "--";
1212  s += x.first;
1213  s += "[label=";
1214  s += std::to_string(x.second);
1215  s += "]";
1216  s += '\n';
1217  }
1218  }
1219  } else {
1220  for (auto &[element, neighbors] : adj) {
1221  for (std::pair<T, double> &x : neighbors) {
1222  if (x.first == element) {
1223  continue;
1224  }
1225  s += std::to_string(element);
1226  s += "--";
1227  s += std::to_string(x.first);
1228  s += "[label=";
1229  s += std::to_string(x.second);
1230  s += "]";
1231  s += '\n';
1232  }
1233  }
1234  }
1235  }
1236  if (_type == "directed") {
1237  digraph_visualization::visualize(s);
1238  } else {
1239  graph_visualization::visualize(s);
1240  }
1241 }
1242 #endif
1243 
1244 #endif
Class for Unweighted Graph.
Definition: graph.h:27
int64_t scc()
scc(strongly connected components) function.
bool bipartite()
bipartite function.
Definition: graph.h:403
void add_edge(T u, T v)
add_edge function
Definition: graph.h:87
std::vector< T > bfs(T start)
bfs function
Definition: graph.h:284
std::vector< std::vector< T > > bridge(T start)
bridge function.
Definition: graph.h:431
graph & operator=(const graph &g)
operator = for the graph class
Definition: graph.h:70
bool has_edge(T start, T end)
has_edge function.
Definition: graph.h:105
friend std::ostream & operator<<(std::ostream &out, graph< T > &g)
operator << for the graph class.
Definition: graph.h:214
std::vector< T > dfs(T start)
dfs function
Definition: graph.h:261
std::vector< T > topological_sort()
topological_sort function.
Definition: graph.h:368
graph(std::string _type, std::vector< std::pair< T, std::vector< T >>> _adj={})
Constructor for the unweighted graph.
Definition: graph.h:35
bool cycle()
cycle function.
Definition: graph.h:338
void visualize()
visualize function.
void clear()
clear function Clearing the entire graph.
Definition: graph.h:121
~graph()
Destroy the graph object.
Definition: graph.h:80
bool connected()
connected function.
Definition: graph.h:444
size_t size()
size function
Definition: graph.h:259
int64_t connected_components()
connected_components function.
Definition: graph.h:310
graph(const graph &g)
Construct a new graph object.
Definition: graph.h:61
int eulerian()
eulerian function.
Definition: graph.h:480
bool empty()
empty function Checks if a graph is empty.
Definition: graph.h:130
class for weighted graph
Definition: graph.h:554
int eulerian()
eulerian function.
Definition: graph.h:1117
int64_t scc()
scc(strongly connected components) function.
double shortest_path(T start, T end)
shortest_path function.
Definition: graph.h:809
int64_t connected_components()
connected_components function.
Definition: graph.h:921
~weighted_graph()
Destroy the weighted graph object.
Definition: graph.h:608
bool bipartite()
bipartite function.
Definition: graph.h:1039
std::vector< std::vector< T > > bridge(T start)
bridge function.
Definition: graph.h:1068
bool has_edge(T start, T end)
has_edge function.
Definition: graph.h:633
weighted_graph(const weighted_graph &g)
Copy constructor for weighted graph class.
Definition: graph.h:586
bool cycle()
cycle function.
Definition: graph.h:949
std::vector< T > topological_sort()
topological sort function.
Definition: graph.h:979
std::vector< T > bfs(T start)
bfs function.
Definition: graph.h:895
friend std::ostream & operator<<(std::ostream &out, weighted_graph< T > &g)
<< operator for the weighted graph class.
Definition: graph.h:761
weighted_graph(std::string _type, std::vector< std::pair< std::pair< T, T >, int64_t >> _adj={})
Constructor for weighted graph.
Definition: graph.h:562
bool empty()
empty function.
Definition: graph.h:657
bool connected()
connected function.
Definition: graph.h:1081
void visualize()
visualize function.
std::unordered_map< T, double > bellman_ford(T start)
find SSSP and identify negative cycles.
Definition: graph.h:1137
std::vector< T > dfs(T start)
dfs function.
Definition: graph.h:868
void add_edge(T u, T v, int64_t w)
add_edge function.
Definition: graph.h:616
size_t size()
size function.
Definition: graph.h:805
void clear()
clear function. Clearing the entire graph.
Definition: graph.h:649
int64_t prim(T start)
prim function.
Definition: graph.h:1014
weighted_graph & operator=(const weighted_graph &g)
operator = for weighted graph class
Definition: graph.h:597