From 7adb0d8d5e534324f9f713b3f0dd19823b6ed768 Mon Sep 17 00:00:00 2001 From: Ayaan Khan Date: Thu, 16 Jul 2020 21:04:29 +0530 Subject: [PATCH 01/31] improved connected components --- graph/connected_components.cpp | 174 ++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 77 deletions(-) diff --git a/graph/connected_components.cpp b/graph/connected_components.cpp index e53dbf424..8b2ce9944 100644 --- a/graph/connected_components.cpp +++ b/graph/connected_components.cpp @@ -15,9 +15,9 @@ *
  * Example - Here is graph with 3 connected components
  *
- *      3   9           6               8
+ *      1   4           5               8
  *     / \ /           / \             / \
- *    2---4           2   7           3   7
+ *    2---3           6   7           9   10
  *
  *    first          second           third
  *    component      component        component
@@ -28,95 +28,115 @@
 #include 
 #include 
 #include 
-
-using std::vector;
+#include 
 
 /**
- * Class for representing graph as a adjacency list.
+ * @namespace graph
+ * @brief Graph Algorithms
  */
-class graph {
- private:
-    /** \brief adj stores adjacency list representation of graph */
-    vector> adj;
 
-    /** \brief keep track of connected components */
-    int connected_components;
+namespace graph {
+  /**
+   * @brief Function that add edge between two nodes or vertices of graph
+   *
+   * @param u any node or vertex of graph
+   * @param v any node or vertex of graph
+   */
+  void addEdge(std::vector> *adj, int u, int v) {
+    (*adj)[u - 1].push_back(v - 1);
+    (*adj)[v - 1].push_back(u - 1);
+  }
 
-    void depth_first_search();
-    void explore(int, vector &);
-
- public:
-    /**
-     * \brief Constructor that intiliazes the graph on creation and set
-     * the connected components to 0
-     */
-    explicit graph(int n) : adj(n, vector()) { connected_components = 0; }
-
-    void addEdge(int, int);
-
-    /**
-     * \brief Function the calculates the connected compoents in the graph
-     * by performing the depth first search on graph
-     *
-     * @return connected_components total connected components in graph
-     */
-    int getConnectedComponents() {
-        depth_first_search();
-        return connected_components;
+  /**
+   * @brief Utility function for depth first seach algorithm
+   * this function explores the vertex which is passed into.
+   *
+   * @param u vertex or node to be explored
+   * @param visited already visited vertices
+   */
+  void explore(const std::vector> *adj, int u,
+      std::vector &visited) {
+    visited[u] = true;
+    for (auto v : (*adj)[u]) {
+      if (!visited[v]) {
+        explore(adj, v, visited);
+      }
     }
-};
+  }
 
-/**
- * \brief Function that add edge between two nodes or vertices of graph
- *
- * @param u any node or vertex of graph
- * @param v any node or vertex of graph
- */
-void graph::addEdge(int u, int v) {
-    adj[u - 1].push_back(v - 1);
-    adj[v - 1].push_back(u - 1);
-}
-
-/**
- * \brief Function that perfoms depth first search algorithm on graph
- */
-void graph::depth_first_search() {
-    int n = adj.size();
-    vector visited(n, false);
+  /**
+   * @brief Function that perfoms depth first search algorithm on graph
+   * and calculated the number of connected components.
+   */
+  int getConnectedComponents(const std::vector> *adj) {
+    int n = adj->size();
+    int connected_components = 0;
+    std::vector visited(n, false);
 
     for (int i = 0; i < n; i++) {
-        if (!visited[i]) {
-            explore(i, visited);
-            connected_components++;
-        }
-    }
-}
-/**
- * \brief Utility function for depth first seach algorithm
- * this function explores the vertex which is passed into.
- *
- * @param u vertex or node to be explored
- * @param visited already visited vertex
- */
-void graph::explore(int u, vector &visited) {
-    visited[u] = true;
-    for (auto v : adj[u]) {
-        if (!visited[v]) {
-            explore(v, visited);
-        }
+      if (!visited[i]) {
+        explore(adj, i, visited);
+        connected_components++;
+      }
     }
+    return connected_components;
+  }
+} // namespace graph
+
+/** Function to test the algorithm */
+void tests() {
+  std::cout << "Running predefined tests..." << std::endl;
+  std::cout << "Initiating Test 1..." << std::endl;
+  std::vector> adj1(9, std::vector());
+  graph::addEdge(&adj1, 1, 2); 
+  graph::addEdge(&adj1, 1, 3); 
+  graph::addEdge(&adj1, 3, 4); 
+  graph::addEdge(&adj1, 5, 7); 
+  graph::addEdge(&adj1, 5, 6); 
+  graph::addEdge(&adj1, 8, 9);
+  
+  assert(graph::getConnectedComponents(&adj1) == 3);
+  std::cout << "Test 1 Passed..." << std::endl;
+
+  std::cout << "Innitiating Test 2..." << std::endl;
+  std::vector> adj2(10, std::vector());
+  graph::addEdge(&adj2, 1, 2);
+  graph::addEdge(&adj2, 1, 3);
+  graph::addEdge(&adj2, 1, 4);
+  graph::addEdge(&adj2, 2, 3);
+  graph::addEdge(&adj2, 3, 4);
+  graph::addEdge(&adj2, 4, 8);
+  graph::addEdge(&adj2, 4, 10);
+  graph::addEdge(&adj2, 8, 10);
+  graph::addEdge(&adj2, 8, 9);
+  graph::addEdge(&adj2, 5, 7);
+  graph::addEdge(&adj2, 5, 6);
+  graph::addEdge(&adj2, 6, 7);
+
+  assert(graph::getConnectedComponents(&adj2) == 2);
+  std::cout << "Test 2 Passed..." << std::endl;
 }
 
 /** Main function */
 int main() {
-    /// creating a graph with 4 vertex
-    graph g(4);
+  /// running predefined tests
+  tests();
+  
+  int vertices, edges;
+  std::cout << "Enter the number of vertices : ";
+  std::cin >> vertices;
+  std::cout << "Enter the number of edges : ";
+  std::cin >> edges;
 
-    /// Adding edges between vertices
-    g.addEdge(1, 2);
-    g.addEdge(3, 2);
+  std::vector> adj(vertices, std::vector());
 
-    /// printing the connected components
-    std::cout << g.getConnectedComponents();
-    return 0;
+  while (edges--) {
+    int u, v;
+    std::cin >> u >> v;
+    graph::addEdge(&adj, u, v);
+  }
+
+  int cc = graph::getConnectedComponents(&adj);
+  std::cout << cc << std::endl;
+  return 0;
 }

From 117c8362bea8568ebd27bc52bc980461e06a560a Mon Sep 17 00:00:00 2001
From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Date: Thu, 16 Jul 2020 15:35:37 +0000
Subject: [PATCH 02/31] formatting source-code for
 7adb0d8d5e534324f9f713b3f0dd19823b6ed768

---
 graph/connected_components.cpp | 156 ++++++++++++++++-----------------
 1 file changed, 78 insertions(+), 78 deletions(-)

diff --git a/graph/connected_components.cpp b/graph/connected_components.cpp
index 8b2ce9944..bfb92c7c8 100644
--- a/graph/connected_components.cpp
+++ b/graph/connected_components.cpp
@@ -26,9 +26,9 @@
  */
 
 #include 
+#include 
 #include 
 #include 
-#include 
 
 /**
  * @namespace graph
@@ -36,107 +36,107 @@
  */
 
 namespace graph {
-  /**
-   * @brief Function that add edge between two nodes or vertices of graph
-   *
-   * @param u any node or vertex of graph
-   * @param v any node or vertex of graph
-   */
-  void addEdge(std::vector> *adj, int u, int v) {
+/**
+ * @brief Function that add edge between two nodes or vertices of graph
+ *
+ * @param u any node or vertex of graph
+ * @param v any node or vertex of graph
+ */
+void addEdge(std::vector> *adj, int u, int v) {
     (*adj)[u - 1].push_back(v - 1);
     (*adj)[v - 1].push_back(u - 1);
-  }
+}
 
-  /**
-   * @brief Utility function for depth first seach algorithm
-   * this function explores the vertex which is passed into.
-   *
-   * @param u vertex or node to be explored
-   * @param visited already visited vertices
-   */
-  void explore(const std::vector> *adj, int u,
-      std::vector &visited) {
+/**
+ * @brief Utility function for depth first seach algorithm
+ * this function explores the vertex which is passed into.
+ *
+ * @param u vertex or node to be explored
+ * @param visited already visited vertices
+ */
+void explore(const std::vector> *adj, int u,
+             std::vector &visited) {
     visited[u] = true;
     for (auto v : (*adj)[u]) {
-      if (!visited[v]) {
-        explore(adj, v, visited);
-      }
+        if (!visited[v]) {
+            explore(adj, v, visited);
+        }
     }
-  }
+}
 
-  /**
-   * @brief Function that perfoms depth first search algorithm on graph
-   * and calculated the number of connected components.
-   */
-  int getConnectedComponents(const std::vector> *adj) {
+/**
+ * @brief Function that perfoms depth first search algorithm on graph
+ * and calculated the number of connected components.
+ */
+int getConnectedComponents(const std::vector> *adj) {
     int n = adj->size();
     int connected_components = 0;
     std::vector visited(n, false);
 
     for (int i = 0; i < n; i++) {
-      if (!visited[i]) {
-        explore(adj, i, visited);
-        connected_components++;
-      }
+        if (!visited[i]) {
+            explore(adj, i, visited);
+            connected_components++;
+        }
     }
     return connected_components;
-  }
-} // namespace graph
+}
+}  // namespace graph
 
 /** Function to test the algorithm */
 void tests() {
-  std::cout << "Running predefined tests..." << std::endl;
-  std::cout << "Initiating Test 1..." << std::endl;
-  std::vector> adj1(9, std::vector());
-  graph::addEdge(&adj1, 1, 2); 
-  graph::addEdge(&adj1, 1, 3); 
-  graph::addEdge(&adj1, 3, 4); 
-  graph::addEdge(&adj1, 5, 7); 
-  graph::addEdge(&adj1, 5, 6); 
-  graph::addEdge(&adj1, 8, 9);
-  
-  assert(graph::getConnectedComponents(&adj1) == 3);
-  std::cout << "Test 1 Passed..." << std::endl;
+    std::cout << "Running predefined tests..." << std::endl;
+    std::cout << "Initiating Test 1..." << std::endl;
+    std::vector> adj1(9, std::vector());
+    graph::addEdge(&adj1, 1, 2);
+    graph::addEdge(&adj1, 1, 3);
+    graph::addEdge(&adj1, 3, 4);
+    graph::addEdge(&adj1, 5, 7);
+    graph::addEdge(&adj1, 5, 6);
+    graph::addEdge(&adj1, 8, 9);
 
-  std::cout << "Innitiating Test 2..." << std::endl;
-  std::vector> adj2(10, std::vector());
-  graph::addEdge(&adj2, 1, 2);
-  graph::addEdge(&adj2, 1, 3);
-  graph::addEdge(&adj2, 1, 4);
-  graph::addEdge(&adj2, 2, 3);
-  graph::addEdge(&adj2, 3, 4);
-  graph::addEdge(&adj2, 4, 8);
-  graph::addEdge(&adj2, 4, 10);
-  graph::addEdge(&adj2, 8, 10);
-  graph::addEdge(&adj2, 8, 9);
-  graph::addEdge(&adj2, 5, 7);
-  graph::addEdge(&adj2, 5, 6);
-  graph::addEdge(&adj2, 6, 7);
+    assert(graph::getConnectedComponents(&adj1) == 3);
+    std::cout << "Test 1 Passed..." << std::endl;
 
-  assert(graph::getConnectedComponents(&adj2) == 2);
-  std::cout << "Test 2 Passed..." << std::endl;
+    std::cout << "Innitiating Test 2..." << std::endl;
+    std::vector> adj2(10, std::vector());
+    graph::addEdge(&adj2, 1, 2);
+    graph::addEdge(&adj2, 1, 3);
+    graph::addEdge(&adj2, 1, 4);
+    graph::addEdge(&adj2, 2, 3);
+    graph::addEdge(&adj2, 3, 4);
+    graph::addEdge(&adj2, 4, 8);
+    graph::addEdge(&adj2, 4, 10);
+    graph::addEdge(&adj2, 8, 10);
+    graph::addEdge(&adj2, 8, 9);
+    graph::addEdge(&adj2, 5, 7);
+    graph::addEdge(&adj2, 5, 6);
+    graph::addEdge(&adj2, 6, 7);
+
+    assert(graph::getConnectedComponents(&adj2) == 2);
+    std::cout << "Test 2 Passed..." << std::endl;
 }
 
 /** Main function */
 int main() {
-  /// running predefined tests
-  tests();
-  
-  int vertices, edges;
-  std::cout << "Enter the number of vertices : ";
-  std::cin >> vertices;
-  std::cout << "Enter the number of edges : ";
-  std::cin >> edges;
+    /// running predefined tests
+    tests();
 
-  std::vector> adj(vertices, std::vector());
+    int vertices, edges;
+    std::cout << "Enter the number of vertices : ";
+    std::cin >> vertices;
+    std::cout << "Enter the number of edges : ";
+    std::cin >> edges;
 
-  while (edges--) {
-    int u, v;
-    std::cin >> u >> v;
-    graph::addEdge(&adj, u, v);
-  }
+    std::vector> adj(vertices, std::vector());
 
-  int cc = graph::getConnectedComponents(&adj);
-  std::cout << cc << std::endl;
-  return 0;
+    while (edges--) {
+        int u, v;
+        std::cin >> u >> v;
+        graph::addEdge(&adj, u, v);
+    }
+
+    int cc = graph::getConnectedComponents(&adj);
+    std::cout << cc << std::endl;
+    return 0;
 }

From f5a35eb8cd8d650a5c1c9a6e50fcdf818055d07b Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 19:52:16 +0530
Subject: [PATCH 03/31] fix: dijkstra.cpp

---
 graph/connected_components.cpp |  24 ++--
 graph/dijkstra.cpp             | 219 ++++++++++++++++++++++++++-------
 2 files changed, 184 insertions(+), 59 deletions(-)

diff --git a/graph/connected_components.cpp b/graph/connected_components.cpp
index 8b2ce9944..55bdccbc7 100644
--- a/graph/connected_components.cpp
+++ b/graph/connected_components.cpp
@@ -55,10 +55,10 @@ namespace graph {
    * @param visited already visited vertices
    */
   void explore(const std::vector> *adj, int u,
-      std::vector &visited) {
-    visited[u] = true;
+      std::vector *visited) {
+    (*visited)[u] = true;
     for (auto v : (*adj)[u]) {
-      if (!visited[v]) {
+      if (!(*visited)[v]) {
         explore(adj, v, visited);
       }
     }
@@ -75,26 +75,26 @@ namespace graph {
 
     for (int i = 0; i < n; i++) {
       if (!visited[i]) {
-        explore(adj, i, visited);
+        explore(adj, i, &visited);
         connected_components++;
       }
     }
     return connected_components;
   }
-} // namespace graph
+}  // namespace graph
 
 /** Function to test the algorithm */
 void tests() {
   std::cout << "Running predefined tests..." << std::endl;
   std::cout << "Initiating Test 1..." << std::endl;
   std::vector> adj1(9, std::vector());
-  graph::addEdge(&adj1, 1, 2); 
-  graph::addEdge(&adj1, 1, 3); 
-  graph::addEdge(&adj1, 3, 4); 
-  graph::addEdge(&adj1, 5, 7); 
-  graph::addEdge(&adj1, 5, 6); 
+  graph::addEdge(&adj1, 1, 2);
+  graph::addEdge(&adj1, 1, 3);
+  graph::addEdge(&adj1, 3, 4);
+  graph::addEdge(&adj1, 5, 7);
+  graph::addEdge(&adj1, 5, 6);
   graph::addEdge(&adj1, 8, 9);
-  
+
   assert(graph::getConnectedComponents(&adj1) == 3);
   std::cout << "Test 1 Passed..." << std::endl;
 
@@ -121,7 +121,7 @@ void tests() {
 int main() {
   /// running predefined tests
   tests();
-  
+
   int vertices, edges;
   std::cout << "Enter the number of vertices : ";
   std::cin >> vertices;
diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
index 650f0cd51..357ecf843 100644
--- a/graph/dijkstra.cpp
+++ b/graph/dijkstra.cpp
@@ -1,52 +1,177 @@
-#include 
+/**
+ * @file
+ * @brief [Graph Dijkstras Shortest Path Algorithm
+ * (Dijkstra's Shortest Path)]
+ * (https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
+ *
+ * @author [Ayaan Khan](http://github.com/ayaankhan98)
+ *
+ * @details
+ * Dijkstra's Algorithm is used to find the shortest path from a source
+ * vertex to all other reachable vertex in the graph.
+ * The algorithm initially assumes all the nodes are unreachable from the
+ * given source vertex so we mark the distances of all vertices as INF
+ * (infinity) from source vertex (INF / infinity denotes unable to reach).
+ *
+ * in similar fashion with BFS we assume the distance of source vertex as 0
+ * and pushes the vertex in a priority queue with it's distance.
+ * we maintain the priority queue as a min heap so that we can get the
+ * minimum element at the top of heap
+ *
+ * Basically what we do in this algorithm is that we try to minimize the
+ * distances of all the reachable vertices from the current vertex, look
+ * at the code below to understand in better way.
+ *
+ */
+#include 
 #include 
 #include 
+#include 
 #include 
-using namespace std;
-#define INF 10000010
-vector> graph[5 * 100001];
-int dis[5 * 100001];
-int dij(vector> *v, int s, int *dis) {
-    priority_queue, vector>,
-                   greater>>
-        pq;
-    // source distance to zero.
-    pq.push(make_pair(0, s));
-    dis[s] = 0;
-    int u;
-    while (!pq.empty()) {
-        u = (pq.top()).second;
-        pq.pop();
-        for (vector>::iterator it = v[u].begin();
-             it != v[u].end(); it++) {
-            if (dis[u] + it->first < dis[it->second]) {
-                dis[it->second] = dis[u] + it->first;
-                pq.push(make_pair(dis[it->second], it->second));
-            }
-        }
-    }
-}
-int main() {
-    int m, n, l, x, y, s;
-    // n--> number of nodes , m --> number of edges
-    cin >> n >> m;
-    for (int i = 0; i < m; i++) {
-        // input edges.
-        scanf("%d%d%d", &x, &y, &l);
-        graph[x].push_back(make_pair(l, y));
-        graph[y].push_back(
-            make_pair(l, x));  // comment this line for directed graph
-    }
-    // start node.
-    scanf("%d", &s);
-    // intialise all distances to infinity.
-    for (int i = 1; i <= n; i++) dis[i] = INF;
-    dij(graph, s, dis);
 
-    for (int i = 1; i <= n; i++)
-        if (dis[i] == INF)
-            cout << "-1 ";
-        else
-            cout << dis[i] << " ";
-    return 0;
+constexpr long long INF = 1000000000;
+
+/**
+ * @namespace graph
+ * @brief Graph Algorithms
+ */
+
+namespace graph {
+  /**
+   * @brief Function that add edge between two nodes or vertices of graph
+   *
+   * @param u any node or vertex of graph
+   * @param v any node or vertex of graph
+   */
+  void addEdge(std::vector>> *adj, int u, int v,
+      int w) {
+    (*adj)[u - 1].push_back(std::make_pair(v - 1, w));
+    // (*adj)[v - 1].push_back(std::make_pair(u - 1, w));
+  }
+  
+  /**
+   * @brief Function runs the dijkstra algorithm for some source vertex and
+   * target vertex in the graph and returns the shortest distance of target
+   * from the source.
+   *
+   * @param adj input graph
+   * @param s source vertex
+   * @param t target vertex
+   * 
+   * @return shortest distance if target is reachable from source else -1 in
+   * case if target is not reachable from source.
+   */
+  int dijkstra(std::vector>> *adj, int s, int t) {
+    /// n denotes the number of vertices in graph
+    int n = adj->size();
+
+    /// setting all the distances initially to INF
+    std::vector dist(n, INF);
+
+    /// creating a min heap using priority queue
+    /// first element of pair contains the distance
+    /// second element of pair contains the vertex
+    std::priority_queue, std::vector>,
+      std::greater>>
+        pq;
+    
+    /// pushing the source vertex 's' with 0 distance in min heap
+    pq.push(std::make_pair(0, s));
+
+    /// marking the distance of source as 0
+    dist[s] = 0;
+
+    while (!pq.empty()) {
+      /// second element of pair denotes the node / vertex
+      int currentNode = pq.top().second;
+
+      /// first element of pair denotes the distance
+      int currentDist = pq.top().first;
+
+      pq.pop();
+
+      /// for all the reachable vertex from the currently exploring vertex
+      /// we will try to minimize the distance
+      for (std::pair edge : (*adj)[currentNode]) {
+
+        /// minimizing distances
+        if (currentDist + edge.second < dist[edge.first]) {
+          dist[edge.first] = currentDist + edge.second;
+          pq.push(std::make_pair(dist[edge.first], edge.first));
+        }
+      }
+    }
+    if (dist[t] != INF) {
+      return dist[t];
+    }
+    return -1;
+  }
+} // namespace graph
+
+/** Function to test the Algorithm */
+void tests() {
+  std::cout << "Initiatinig Predefined Tests..." << std::endl;
+  std::cout << "Initiating Test 1..." << std::endl;
+  std::vector>> adj1(4, std::vector>());
+  graph::addEdge(&adj1, 1, 2, 1);
+  graph::addEdge(&adj1, 4, 1, 2);
+  graph::addEdge(&adj1, 2, 3, 2);
+  graph::addEdge(&adj1, 1, 3, 5);
+
+  int s = 1, t = 3;
+  assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3);
+  std::cout << "Test 1 Passed..." << std::endl;
+
+  s = 4, t = 3;
+  std::cout << "Initiating Test 2..." << std::endl;
+  assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5);
+  std::cout << "Test 2 Passed..." << std::endl;
+
+  std::vector>> adj2(5, std::vector>());
+  graph::addEdge(&adj2, 1, 2, 4);
+  graph::addEdge(&adj2, 1, 3, 2);
+  graph::addEdge(&adj2, 2, 3, 2);
+  graph::addEdge(&adj2, 3, 2, 1);
+  graph::addEdge(&adj2, 2, 4, 2);
+  graph::addEdge(&adj2, 3, 5, 4);
+  graph::addEdge(&adj2, 5, 4, 1);
+  graph::addEdge(&adj2, 2, 5, 3);
+  graph::addEdge(&adj2, 3, 4, 4);
+
+  s = 1, t = 5;
+  std::cout << "Initiating Test 3..." << std::endl;
+  assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6);
+  std::cout << "Test 3 Passed..." << std::endl;
+  std::cout << "All Test Passed..." << std::endl << std::endl;
+}
+
+/** Main function */
+int main(){
+  // running predefined tests
+  tests();
+
+  int vertices, edges;
+  std::cout << "Enter the number of vertices : ";
+  std::cin >> vertices;
+  std::cout << "Enter the number of edges : ";
+  std::cin >> edges;
+
+  std::vector>> adj(
+      vertices, std::vector>());
+
+  int u, v, w;
+  while (edges--) {
+    std::cin >> u >> v >> w;
+    graph::addEdge(&adj, u, v, w);
+  }
+
+  int s, t;
+  std::cin >> s >> t;
+  int dist = graph::dijkstra(&adj, s-1, t-1);
+  if (dist == -1) {
+    std::cout << "Target not reachable from source" << std::endl;
+  } else {
+    std::cout << "Shortest Path Distance : " << dist << std::endl;
+  }
+  return 0;
 }

From 541d3bfbcff70bbb81aad2b0080d8afd426e0da9 Mon Sep 17 00:00:00 2001
From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Date: Fri, 17 Jul 2020 14:27:01 +0000
Subject: [PATCH 04/31] formatting source-code for
 56556a81fbb1ff545f80cdf204e4bdfc3223d55c

---
 graph/dijkstra.cpp | 191 +++++++++++++++++++++++----------------------
 1 file changed, 96 insertions(+), 95 deletions(-)

diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
index 357ecf843..3dca9e64a 100644
--- a/graph/dijkstra.cpp
+++ b/graph/dijkstra.cpp
@@ -37,31 +37,31 @@ constexpr long long INF = 1000000000;
  */
 
 namespace graph {
-  /**
-   * @brief Function that add edge between two nodes or vertices of graph
-   *
-   * @param u any node or vertex of graph
-   * @param v any node or vertex of graph
-   */
-  void addEdge(std::vector>> *adj, int u, int v,
-      int w) {
+/**
+ * @brief Function that add edge between two nodes or vertices of graph
+ *
+ * @param u any node or vertex of graph
+ * @param v any node or vertex of graph
+ */
+void addEdge(std::vector>> *adj, int u, int v,
+             int w) {
     (*adj)[u - 1].push_back(std::make_pair(v - 1, w));
     // (*adj)[v - 1].push_back(std::make_pair(u - 1, w));
-  }
-  
-  /**
-   * @brief Function runs the dijkstra algorithm for some source vertex and
-   * target vertex in the graph and returns the shortest distance of target
-   * from the source.
-   *
-   * @param adj input graph
-   * @param s source vertex
-   * @param t target vertex
-   * 
-   * @return shortest distance if target is reachable from source else -1 in
-   * case if target is not reachable from source.
-   */
-  int dijkstra(std::vector>> *adj, int s, int t) {
+}
+
+/**
+ * @brief Function runs the dijkstra algorithm for some source vertex and
+ * target vertex in the graph and returns the shortest distance of target
+ * from the source.
+ *
+ * @param adj input graph
+ * @param s source vertex
+ * @param t target vertex
+ *
+ * @return shortest distance if target is reachable from source else -1 in
+ * case if target is not reachable from source.
+ */
+int dijkstra(std::vector>> *adj, int s, int t) {
     /// n denotes the number of vertices in graph
     int n = adj->size();
 
@@ -72,9 +72,9 @@ namespace graph {
     /// first element of pair contains the distance
     /// second element of pair contains the vertex
     std::priority_queue, std::vector>,
-      std::greater>>
+                        std::greater>>
         pq;
-    
+
     /// pushing the source vertex 's' with 0 distance in min heap
     pq.push(std::make_pair(0, s));
 
@@ -82,96 +82,97 @@ namespace graph {
     dist[s] = 0;
 
     while (!pq.empty()) {
-      /// second element of pair denotes the node / vertex
-      int currentNode = pq.top().second;
+        /// second element of pair denotes the node / vertex
+        int currentNode = pq.top().second;
 
-      /// first element of pair denotes the distance
-      int currentDist = pq.top().first;
+        /// first element of pair denotes the distance
+        int currentDist = pq.top().first;
 
-      pq.pop();
+        pq.pop();
 
-      /// for all the reachable vertex from the currently exploring vertex
-      /// we will try to minimize the distance
-      for (std::pair edge : (*adj)[currentNode]) {
-
-        /// minimizing distances
-        if (currentDist + edge.second < dist[edge.first]) {
-          dist[edge.first] = currentDist + edge.second;
-          pq.push(std::make_pair(dist[edge.first], edge.first));
+        /// for all the reachable vertex from the currently exploring vertex
+        /// we will try to minimize the distance
+        for (std::pair edge : (*adj)[currentNode]) {
+            /// minimizing distances
+            if (currentDist + edge.second < dist[edge.first]) {
+                dist[edge.first] = currentDist + edge.second;
+                pq.push(std::make_pair(dist[edge.first], edge.first));
+            }
         }
-      }
     }
     if (dist[t] != INF) {
-      return dist[t];
+        return dist[t];
     }
     return -1;
-  }
-} // namespace graph
+}
+}  // namespace graph
 
 /** Function to test the Algorithm */
 void tests() {
-  std::cout << "Initiatinig Predefined Tests..." << std::endl;
-  std::cout << "Initiating Test 1..." << std::endl;
-  std::vector>> adj1(4, std::vector>());
-  graph::addEdge(&adj1, 1, 2, 1);
-  graph::addEdge(&adj1, 4, 1, 2);
-  graph::addEdge(&adj1, 2, 3, 2);
-  graph::addEdge(&adj1, 1, 3, 5);
+    std::cout << "Initiatinig Predefined Tests..." << std::endl;
+    std::cout << "Initiating Test 1..." << std::endl;
+    std::vector>> adj1(
+        4, std::vector>());
+    graph::addEdge(&adj1, 1, 2, 1);
+    graph::addEdge(&adj1, 4, 1, 2);
+    graph::addEdge(&adj1, 2, 3, 2);
+    graph::addEdge(&adj1, 1, 3, 5);
 
-  int s = 1, t = 3;
-  assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3);
-  std::cout << "Test 1 Passed..." << std::endl;
+    int s = 1, t = 3;
+    assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3);
+    std::cout << "Test 1 Passed..." << std::endl;
 
-  s = 4, t = 3;
-  std::cout << "Initiating Test 2..." << std::endl;
-  assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5);
-  std::cout << "Test 2 Passed..." << std::endl;
+    s = 4, t = 3;
+    std::cout << "Initiating Test 2..." << std::endl;
+    assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5);
+    std::cout << "Test 2 Passed..." << std::endl;
 
-  std::vector>> adj2(5, std::vector>());
-  graph::addEdge(&adj2, 1, 2, 4);
-  graph::addEdge(&adj2, 1, 3, 2);
-  graph::addEdge(&adj2, 2, 3, 2);
-  graph::addEdge(&adj2, 3, 2, 1);
-  graph::addEdge(&adj2, 2, 4, 2);
-  graph::addEdge(&adj2, 3, 5, 4);
-  graph::addEdge(&adj2, 5, 4, 1);
-  graph::addEdge(&adj2, 2, 5, 3);
-  graph::addEdge(&adj2, 3, 4, 4);
+    std::vector>> adj2(
+        5, std::vector>());
+    graph::addEdge(&adj2, 1, 2, 4);
+    graph::addEdge(&adj2, 1, 3, 2);
+    graph::addEdge(&adj2, 2, 3, 2);
+    graph::addEdge(&adj2, 3, 2, 1);
+    graph::addEdge(&adj2, 2, 4, 2);
+    graph::addEdge(&adj2, 3, 5, 4);
+    graph::addEdge(&adj2, 5, 4, 1);
+    graph::addEdge(&adj2, 2, 5, 3);
+    graph::addEdge(&adj2, 3, 4, 4);
 
-  s = 1, t = 5;
-  std::cout << "Initiating Test 3..." << std::endl;
-  assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6);
-  std::cout << "Test 3 Passed..." << std::endl;
-  std::cout << "All Test Passed..." << std::endl << std::endl;
+    s = 1, t = 5;
+    std::cout << "Initiating Test 3..." << std::endl;
+    assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6);
+    std::cout << "Test 3 Passed..." << std::endl;
+    std::cout << "All Test Passed..." << std::endl << std::endl;
 }
 
 /** Main function */
-int main(){
-  // running predefined tests
-  tests();
+int main() {
+    // running predefined tests
+    tests();
 
-  int vertices, edges;
-  std::cout << "Enter the number of vertices : ";
-  std::cin >> vertices;
-  std::cout << "Enter the number of edges : ";
-  std::cin >> edges;
+    int vertices, edges;
+    std::cout << "Enter the number of vertices : ";
+    std::cin >> vertices;
+    std::cout << "Enter the number of edges : ";
+    std::cin >> edges;
 
-  std::vector>> adj(
-      vertices, std::vector>());
+    std::vector>> adj(
+        vertices, std::vector>());
 
-  int u, v, w;
-  while (edges--) {
-    std::cin >> u >> v >> w;
-    graph::addEdge(&adj, u, v, w);
-  }
+    int u, v, w;
+    while (edges--) {
+        std::cin >> u >> v >> w;
+        graph::addEdge(&adj, u, v, w);
+    }
 
-  int s, t;
-  std::cin >> s >> t;
-  int dist = graph::dijkstra(&adj, s-1, t-1);
-  if (dist == -1) {
-    std::cout << "Target not reachable from source" << std::endl;
-  } else {
-    std::cout << "Shortest Path Distance : " << dist << std::endl;
-  }
-  return 0;
+    int s, t;
+    std::cin >> s >> t;
+    int dist = graph::dijkstra(&adj, s - 1, t - 1);
+    if (dist == -1) {
+        std::cout << "Target not reachable from source" << std::endl;
+    } else {
+        std::cout << "Shortest Path Distance : " << dist << std::endl;
+    }
+    return 0;
 }

From 54fd71569f935df6ad53a74a94745e3d01ec2611 Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 20:32:32 +0530
Subject: [PATCH 05/31] Added CMakeLists.txt

---
 CMakeLists.txt       |  2 +-
 graph/CMakeLists.txt | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
 create mode 100644 graph/CMakeLists.txt

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 712c3db42..8f860eb11 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -76,7 +76,7 @@ add_subdirectory(probability)
 add_subdirectory(data_structures)
 add_subdirectory(machine_learning)
 add_subdirectory(numerical_methods)
-
+add_subdirectory(graph)
 set(CPACK_PROJECT_NAME ${PROJECT_NAME})
 set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
 include(CPack)
diff --git a/graph/CMakeLists.txt b/graph/CMakeLists.txt
new file mode 100644
index 000000000..e00516075
--- /dev/null
+++ b/graph/CMakeLists.txt
@@ -0,0 +1,20 @@
+# If necessary, use the RELATIVE flag, otherwise each source file may be listed
+# with full pathname. RELATIVE may makes it easier to extract an executable name
+# automatically.
+file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
+# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
+# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
+foreach( testsourcefile ${APP_SOURCES} )
+    # I used a simple string replace, to cut off .cpp.
+    string( REPLACE ".cpp" "" testname ${testsourcefile} )
+    add_executable( ${testname} ${testsourcefile} )
+
+    set_target_properties(${testname} PROPERTIES
+        LINKER_LANGUAGE CXX
+        CXX_STANDARD 14)
+    if(OpenMP_CXX_FOUND)
+        target_link_libraries(${testname} OpenMP::OpenMP_CXX)
+    endif()
+    install(TARGETS ${testname} DESTINATION "bin/graph")
+
+endforeach( testsourcefile ${APP_SOURCES} )

From 530da97aec01cfc1a1a0132a4875ea62a746858e Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 20:49:00 +0530
Subject: [PATCH 06/31] fix: infinity

---
 graph/dijkstra.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
index 3dca9e64a..9b47e446f 100644
--- a/graph/dijkstra.cpp
+++ b/graph/dijkstra.cpp
@@ -28,8 +28,9 @@
 #include 
 #include 
 #include 
+#include 
 
-constexpr long long INF = 1000000000;
+constexpr long long INF = std::numeric_limits::max();
 
 /**
  * @namespace graph
@@ -66,7 +67,7 @@ int dijkstra(std::vector>> *adj, int s, int t) {
     int n = adj->size();
 
     /// setting all the distances initially to INF
-    std::vector dist(n, INF);
+    std::vector dist(n, INF);
 
     /// creating a min heap using priority queue
     /// first element of pair contains the distance

From eb10e84a15243a4ed5463b6d268dd5c013f71e68 Mon Sep 17 00:00:00 2001
From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Date: Fri, 17 Jul 2020 15:20:20 +0000
Subject: [PATCH 07/31] formatting source-code for
 530da97aec01cfc1a1a0132a4875ea62a746858e

---
 graph/dijkstra.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
index 9b47e446f..620c0215c 100644
--- a/graph/dijkstra.cpp
+++ b/graph/dijkstra.cpp
@@ -25,10 +25,10 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
-#include 
 
 constexpr long long INF = std::numeric_limits::max();
 

From d141abaeb895377dc72dd5b19e486e1e2afe05af Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 21:42:28 +0530
Subject: [PATCH 08/31] Update graph/CMakeLists.txt

Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com>
---
 graph/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/graph/CMakeLists.txt b/graph/CMakeLists.txt
index e00516075..02b8f4840 100644
--- a/graph/CMakeLists.txt
+++ b/graph/CMakeLists.txt
@@ -11,7 +11,7 @@ foreach( testsourcefile ${APP_SOURCES} )
 
     set_target_properties(${testname} PROPERTIES
         LINKER_LANGUAGE CXX
-        CXX_STANDARD 14)
+    )
     if(OpenMP_CXX_FOUND)
         target_link_libraries(${testname} OpenMP::OpenMP_CXX)
     endif()

From 483e00c67e462f4d8b1ad9eb5a069da976a3dfa0 Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 21:46:17 +0530
Subject: [PATCH 09/31] Update CMakeLists.txt

Co-authored-by: David Leal 
---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index da75802a5..29e8c2783 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -87,4 +87,4 @@ endif()
 
 set(CPACK_PROJECT_NAME ${PROJECT_NAME})
 set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
-include(CPack)
\ No newline at end of file
+include(CPack)

From 00233391820855bd63f4b9db98c57df4ce6a8463 Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Fri, 17 Jul 2020 22:40:58 +0530
Subject: [PATCH 10/31] fix: clang-tidy errors

---
 graph/connected_components.cpp | 26 ++++++++++++++++----------
 graph/dijkstra.cpp             | 13 +++++++------
 2 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/graph/connected_components.cpp b/graph/connected_components.cpp
index bfb92c7c8..06bb1ee50 100644
--- a/graph/connected_components.cpp
+++ b/graph/connected_components.cpp
@@ -39,8 +39,9 @@ namespace graph {
 /**
  * @brief Function that add edge between two nodes or vertices of graph
  *
- * @param u any node or vertex of graph
- * @param v any node or vertex of graph
+ * @param adj adjacency list of graph.
+ * @param u any node or vertex of graph.
+ * @param v any node or vertex of graph.
  */
 void addEdge(std::vector> *adj, int u, int v) {
     (*adj)[u - 1].push_back(v - 1);
@@ -51,14 +52,15 @@ void addEdge(std::vector> *adj, int u, int v) {
  * @brief Utility function for depth first seach algorithm
  * this function explores the vertex which is passed into.
  *
- * @param u vertex or node to be explored
- * @param visited already visited vertices
+ * @param adj adjacency list of graph.
+ * @param u vertex or node to be explored.
+ * @param visited already visited vertices.
  */
 void explore(const std::vector> *adj, int u,
-             std::vector &visited) {
-    visited[u] = true;
+             std::vector *visited) {
+    (*visited)[u] = true;
     for (auto v : (*adj)[u]) {
-        if (!visited[v]) {
+        if (!(*visited)[v]) {
             explore(adj, v, visited);
         }
     }
@@ -67,6 +69,10 @@ void explore(const std::vector> *adj, int u,
 /**
  * @brief Function that perfoms depth first search algorithm on graph
  * and calculated the number of connected components.
+ *
+ * @param adj adjacency list of graph.
+ *
+ * @return connected_components number of connected components in graph.
  */
 int getConnectedComponents(const std::vector> *adj) {
     int n = adj->size();
@@ -75,7 +81,7 @@ int getConnectedComponents(const std::vector> *adj) {
 
     for (int i = 0; i < n; i++) {
         if (!visited[i]) {
-            explore(adj, i, visited);
+            explore(adj, i, &visited);
             connected_components++;
         }
     }
@@ -122,7 +128,7 @@ int main() {
     /// running predefined tests
     tests();
 
-    int vertices, edges;
+    int vertices = int(), edges = int();
     std::cout << "Enter the number of vertices : ";
     std::cin >> vertices;
     std::cout << "Enter the number of edges : ";
@@ -130,8 +136,8 @@ int main() {
 
     std::vector> adj(vertices, std::vector());
 
+    int u = int(), v = int();
     while (edges--) {
-        int u, v;
         std::cin >> u >> v;
         graph::addEdge(&adj, u, v);
     }
diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp
index 620c0215c..90fb0ec4f 100644
--- a/graph/dijkstra.cpp
+++ b/graph/dijkstra.cpp
@@ -29,8 +29,9 @@
 #include 
 #include 
 #include 
+#include 
 
-constexpr long long INF = std::numeric_limits::max();
+constexpr int64_t INF = std::numeric_limits::max();
 
 /**
  * @namespace graph
@@ -67,13 +68,13 @@ int dijkstra(std::vector>> *adj, int s, int t) {
     int n = adj->size();
 
     /// setting all the distances initially to INF
-    std::vector dist(n, INF);
+    std::vector dist(n, INF);
 
     /// creating a min heap using priority queue
     /// first element of pair contains the distance
     /// second element of pair contains the vertex
     std::priority_queue, std::vector>,
-                        std::greater>>
+                        std::greater<>>
         pq;
 
     /// pushing the source vertex 's' with 0 distance in min heap
@@ -152,7 +153,7 @@ int main() {
     // running predefined tests
     tests();
 
-    int vertices, edges;
+    int vertices = int(), edges = int();
     std::cout << "Enter the number of vertices : ";
     std::cin >> vertices;
     std::cout << "Enter the number of edges : ";
@@ -161,13 +162,13 @@ int main() {
     std::vector>> adj(
         vertices, std::vector>());
 
-    int u, v, w;
+    int u = int(), v = int(), w = int();
     while (edges--) {
         std::cin >> u >> v >> w;
         graph::addEdge(&adj, u, v, w);
     }
 
-    int s, t;
+    int s = int(), t = int();
     std::cin >> s >> t;
     int dist = graph::dijkstra(&adj, s - 1, t - 1);
     if (dist == -1) {

From cbb43c90aa2ebe69c32fcb095d946c350e85f60c Mon Sep 17 00:00:00 2001
From: Ayaan Khan 
Date: Sat, 25 Jul 2020 07:55:30 +0530
Subject: [PATCH 11/31] fix: build

---
 graph/bfs.cpp                                 | 240 +++++++++---
 .../bridge_finding_with_tarjan_algorithm.cpp  |   2 +
 graph/cycle_check_directed_graph.cpp          | 345 +++---------------
 graph/dfs.cpp                                 | 141 ++++++-
 graph/dijkstra.cpp                            | 184 +++++-----
 graph/kosaraju.cpp                            |  30 +-
 graph/kruskal.cpp                             |   2 +
 graph/lca.cpp                                 |  22 +-
 graph/topological_sort.cpp                    |  21 +-
 9 files changed, 494 insertions(+), 493 deletions(-)

diff --git a/graph/bfs.cpp b/graph/bfs.cpp
index 3acee8f80..31f9c0770 100644
--- a/graph/bfs.cpp
+++ b/graph/bfs.cpp
@@ -1,62 +1,196 @@
+/**
+ *
+ * \file
+ * \brief [Breadth First Search Algorithm
+ * (Breadth First Search)](https://en.wikipedia.org/wiki/Breadth-first_search)
+ *
+ * \author [Ayaan Khan](http://github.com/ayaankhan98)
+ *
+ * \details
+ * Breadth First Search also quoted as BFS is a Graph Traversal Algorithm.
+ * Time Complexity O(|V| + |E|) where V are the number of vertices and E
+ * are the number of edges in the graph.
+ *
+ * Applications of Breadth First Search are
+ *
+ * 1. Finding shortest path between two vertices say u and v, with path
+ *    length measured by number of edges (an advantage over depth first
+ *    search algorithm)
+ * 2. Ford-Fulkerson Method for computing the maximum flow in a flow network.
+ * 3. Testing bipartiteness of a graph.
+ * 4. Cheney's Algorithm, Copying garbage collection.
+ *
+ * And there are many more...
+ *
+ * 

working

+ * In the implementation below we first created a graph using the adjacency + * list representation of graph. + * Breadth First Search Works as follows + * it requires a vertex as a start vertex, Start vertex is that vertex + * from where you want to start traversing the graph. + * we maintain a bool array or a vector to keep track of the vertices + * which we have visited so that we do not traverse the visited vertices + * again and again and eventually fall into an infinite loop. Along with this + * boolen array we use a Queue. + * + * 1. First we mark the start vertex as visited. + * 2. Push this visited vertex in the Queue. + * 3. while the queue is not empty we repeat the following steps + * + * 1. Take out an element from the front of queue + * 2. start exploring the adjacency list of this vertex + * if element in the adjacency list is not visited then we + * push that element into the queue and mark this as visited + * + */ +#include +#include #include -using namespace std; -class graph { - int v; - list *adj; +#include +#include - public: - graph(int v); - void addedge(int src, int dest); - void printgraph(); - void bfs(int s); -}; -graph::graph(int v) { - this->v = v; - this->adj = new list[v]; +/** + * \namespace graph + * \brief Graph algorithms + */ +namespace graph { +/** + * \brief + * Adds and edge between two vertices of graph say u and v in this + * case. + * + * @param adj Adjacency list representation of graph + * @param u first vertex + * @param v second vertex + * + */ +void addEdge(std::vector> *adj, int u, int v) { + /** + * Here we are considering directed graph that's the + * reason we are adding v to the adjacency list representation of u + * but not adding u to the adjacency list representation of v + * + * in case of a un-directed graph you can un comment the statement below. + */ + (*adj)[u - 1].push_back(v - 1); + // adj[v - 1].push_back(u -1); } -void graph::addedge(int src, int dest) { - src--; - dest--; - adj[src].push_back(dest); - // adj[dest].push_back(src); -} -void graph::printgraph() { - for (int i = 0; i < this->v; i++) { - cout << "Adjacency list of vertex " << i + 1 << " is \n"; - list::iterator it; - for (it = adj[i].begin(); it != adj[i].end(); ++it) { - cout << *it + 1 << " "; - } - cout << endl; - } -} -void graph::bfs(int s) { - bool *visited = new bool[this->v + 1]; - memset(visited, false, sizeof(bool) * (this->v + 1)); - visited[s] = true; - list q; - q.push_back(s); - list::iterator it; - while (!q.empty()) { - int u = q.front(); - cout << u << " "; - q.pop_front(); - for (it = adj[u].begin(); it != adj[u].end(); ++it) { - if (visited[*it] == false) { - visited[*it] = true; - q.push_back(*it); + +/** + * \brief + * Function performs the breadth first search algorithm over the graph + * + * @param adj Adjacency list representation of graph + * @param start vertex from where traversing starts + * + */ +std::vector beadth_first_search(const std::vector> &adj, + int start) { + size_t vertices = adj.size(); + + std::vector result; + + /// vector to keep track of visited vertices + std::vector visited(vertices, 0); + + std::queue tracker; + /// marking the start vertex as visited + visited[start] = true; + tracker.push(start); + while (!tracker.empty()) { + size_t vertex = tracker.front(); + tracker.pop(); + result.push_back(vertex + 1); + for (auto x : adj[vertex]) { + /// if the vertex is not visited then mark this as visited + /// and push it to the queue + if (!visited[x]) { + visited[x] = true; + tracker.push(x); } } } + return result; } +} // namespace graph + +void tests() { + std::cout << "Initiating Tests" << std::endl; + + /// Test 1 Begin + std::vector> graphData(4, std::vector()); + graph::addEdge(&graphData, 1, 2); + graph::addEdge(&graphData, 1, 3); + graph::addEdge(&graphData, 2, 3); + graph::addEdge(&graphData, 3, 1); + graph::addEdge(&graphData, 3, 4); + graph::addEdge(&graphData, 4, 4); + + std::vector returnedResult = graph::beadth_first_search(graphData, 2); + std::vector correctResult = {3, 1, 4, 2}; + + assert(std::equal(correctResult.begin(), correctResult.end(), + returnedResult.begin())); + std::cout << "Test 1 Passed..." << std::endl; + + /// Test 2 Begin + /// clear data from previous test + returnedResult.clear(); + correctResult.clear(); + + returnedResult = graph::beadth_first_search(graphData, 0); + correctResult = {1, 2, 3, 4}; + + assert(std::equal(correctResult.begin(), correctResult.end(), + returnedResult.begin())); + std::cout << "Test 2 Passed..." << std::endl; + + /// Test 3 Begins + /// clear data from previous test + graphData.clear(); + returnedResult.clear(); + correctResult.clear(); + + graphData.resize(6); + graph::addEdge(&graphData, 1, 2); + graph::addEdge(&graphData, 1, 3); + graph::addEdge(&graphData, 2, 4); + graph::addEdge(&graphData, 3, 4); + graph::addEdge(&graphData, 2, 5); + graph::addEdge(&graphData, 4, 6); + + returnedResult = graph::beadth_first_search(graphData, 0); + correctResult = {1, 2, 3, 4, 5, 6}; + + assert(std::equal(correctResult.begin(), correctResult.end(), + returnedResult.begin())); + std::cout << "Test 3 Passed..." << std::endl; +} + +/** Main function */ int main() { - graph g(4); - g.addedge(1, 2); - g.addedge(2, 3); - g.addedge(3, 4); - g.addedge(1, 4); - g.addedge(1, 3); - // g.printgraph(); - g.bfs(2); + /// running predefined test cases + tests(); + + size_t vertices, edges; + std::cout << "Enter the number of vertices : "; + std::cin >> vertices; + std::cout << "Enter the number of edges : "; + std::cin >> edges; + + /// creating a graph + std::vector> adj(vertices, std::vector()); + + /// taking input for edges + std::cout << "Enter vertices in pair which have edges between them : " + << std::endl; + while (edges--) { + int u, v; + std::cin >> u >> v; + graph::addEdge(&adj, u, v); + } + + /// running Breadth First Search Algorithm on the graph + graph::beadth_first_search(adj, 0); return 0; -} +} \ No newline at end of file diff --git a/graph/bridge_finding_with_tarjan_algorithm.cpp b/graph/bridge_finding_with_tarjan_algorithm.cpp index eec176af5..2b54e1b96 100644 --- a/graph/bridge_finding_with_tarjan_algorithm.cpp +++ b/graph/bridge_finding_with_tarjan_algorithm.cpp @@ -7,9 +7,11 @@ #include // for min & max #include // for cout #include // for std::vector + using std::cout; using std::min; using std::vector; + class Solution { vector> graph; vector in_time, out_time; diff --git a/graph/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp index 0f7b84cd3..c991730c0 100644 --- a/graph/cycle_check_directed_graph.cpp +++ b/graph/cycle_check_directed_graph.cpp @@ -1,302 +1,57 @@ -/** - * Copyright 2020 - * @file cycle_check_directed graph.cpp - * - * @brief BFS and DFS algorithms to check for cycle in a directed graph. - * - * @author Anmol3299 - * contact: mittalanmol22@gmail.com - * - */ +#include +#include +#include +using std::vector; +using std::pair; -#include // for std::cout -#include // for std::queue -#include // for throwing errors -#include // for std::remove_reference_t -#include // for std::unordered_map -#include // for std::move -#include // for std::vector - -/** - * Implementation of non-weighted directed edge of a graph. - * - * The source vertex of the edge is labelled "src" and destination vertex is - * labelled "dest". - */ -struct Edge { - unsigned int src; - unsigned int dest; - - Edge() = delete; - ~Edge() = default; - Edge(Edge&&) = default; - Edge& operator=(Edge&&) = default; - Edge(Edge const&) = default; - Edge& operator=(Edge const&) = default; - - /** Set the source and destination of the vertex. - * - * @param source is the source vertex of the edge. - * @param destination is the destination vertex of the edge. - */ - Edge(unsigned int source, unsigned int destination) - : src(source), dest(destination) {} +void explore(int i, vector> &adj, int *state) +{ + state[i] = 1; + for(auto it2 : adj[i]) + { + if (state[it2] == 0) + { + explore(it2, adj,state); + } + if (state[it2] == 1) + { + std::cout<<"1"; + exit(0); + } + } + state[i] = 2; }; +int acyclic(vector > &adj,size_t n) { + //write your code here -using AdjList = std::unordered_map>; + int state[n]; // permitted states are 0 1 and 2 -/** - * Implementation of graph class. - * - * The graph will be represented using Adjacency List representation. - * This class contains 2 data members "m_vertices" & "m_adjList" used to - * represent the number of vertices and adjacency list of the graph - * respectively. The vertices are labelled 0 - (m_vertices - 1). - */ -class Graph { - public: - Graph() : m_vertices(0), m_adjList({}) {} - ~Graph() = default; - Graph(Graph&&) = default; - Graph& operator=(Graph&&) = default; - Graph(Graph const&) = default; - Graph& operator=(Graph const&) = default; + // mark the states of all vertices initially to 0 + for(int i=0;i const& edges) - : m_vertices(vertices) { - for (auto const& edge : edges) { - if (edge.src >= vertices || edge.dest >= vertices) { - throw std::range_error( - "Either src or dest of edge out of range"); - } - m_adjList[edge.src].emplace_back(edge.dest); - } + for(auto it1 = 0; it1 != adj.size(); it1++) + { + if (state[it1] == 0) + explore(it1,adj,state); + if (state[it1] == 1) + { + std::cout<<"1"; + exit(0); } - - /** Return a const reference of the adjacency list. - * - * @return const reference to the adjacency list - */ - std::remove_reference_t const& getAdjList() const { - return m_adjList; - } - - /** - * @return number of vertices in the graph. - */ - std::remove_reference_t const& getVertices() const { - return m_vertices; - } - - /** Add vertices in the graph. - * - * @param num is the number of vertices to be added. It adds 1 vertex by - * default. - * - */ - void addVertices(unsigned int num = 1) { m_vertices += num; } - - /** Add an edge in the graph. - * - * @param edge that needs to be added. - */ - void addEdge(Edge const& edge) { - if (edge.src >= m_vertices || edge.dest >= m_vertices) { - throw std::range_error("Either src or dest of edge out of range"); - } - m_adjList[edge.src].emplace_back(edge.dest); - } - - /** Add an Edge in the graph - * - * @param source is source vertex of the edge. - * @param destination is the destination vertex of the edge. - */ - void addEdge(unsigned int source, unsigned int destination) { - if (source >= m_vertices || destination >= m_vertices) { - throw std::range_error( - "Either source or destination of edge out of range"); - } - m_adjList[source].emplace_back(destination); - } - - private: - unsigned int m_vertices; - AdjList m_adjList; -}; - -class CycleCheck { - private: - enum nodeStates : uint8_t { not_visited = 0, in_stack, visited }; - - /** Helper function of "isCyclicDFS". - * - * @param adjList is the adjacency list representation of some graph. - * @param state is the state of the nodes of the graph. - * @param node is the node being evaluated. - * - * @return true if graph has a cycle, else false. - */ - static bool isCyclicDFSHelper(AdjList const& adjList, - std::vector* state, - unsigned int node) { - // Add node "in_stack" state. - (*state)[node] = in_stack; - - // If the node has children, then recursively visit all children of the - // node. - if (auto const& it = adjList.find(node); it != adjList.end()) { - for (auto child : it->second) { - // If state of child node is "not_visited", evaluate that child - // for presence of cycle. - if (auto state_of_child = (*state)[child]; - state_of_child == not_visited) { - if (isCyclicDFSHelper(adjList, state, child)) { - return true; - } - } else if (state_of_child == in_stack) { - // If child node was "in_stack", then that means that there - // is a cycle in the graph. Return true for presence of the - // cycle. - return true; - } - } - } - - // Current node has been evaluated for the presence of cycle and had no - // cycle. Mark current node as "visited". - (*state)[node] = visited; - // Return that current node didn't result in any cycles. - return false; - } - - public: - /** Driver function to check if a graph has a cycle. - * - * This function uses DFS to check for cycle in the graph. - * - * @param graph which needs to be evaluated for the presence of cycle. - * @return true if a cycle is detected, else false. - */ - static bool isCyclicDFS(Graph const& graph) { - /** State of the node. - * - * It is a vector of "nodeStates" which represents the state node is in. - * It can take only 3 values: "not_visited", "in_stack", and "visited". - * - * Initially, all nodes are in "not_visited" state. - */ - std::vector state(graph.getVertices(), not_visited); - - // Start visiting each node. - for (auto node = 0; node < graph.getVertices(); node++) { - // If a node is not visited, only then check for presence of cycle. - // There is no need to check for presence of cycle for a visited - // node as it has already been checked for presence of cycle. - if (state[node] == not_visited) { - // Check for cycle. - if (isCyclicDFSHelper(graph.getAdjList(), &state, node)) { - return true; - } - } - } - - // All nodes have been safely traversed, that means there is no cycle in - // the graph. Return false. - return false; - } - - /** Check if a graph has cycle or not. - * - * This function uses BFS to check if a graph is cyclic or not. - * - * @param graph which needs to be evaluated for the presence of cycle. - * @return true if a cycle is detected, else false. - */ - static bool isCyclicBFS(Graph const& graph) { - AdjList graphAjdList = graph.getAdjList(); - - std::vector indegree(graph.getVertices(), 0); - // Calculate the indegree i.e. the number of incident edges to the node. - for (auto const& [parent, children] : graphAjdList) { - for (auto const& child : children) { - indegree[child]++; - } - } - - std::queue can_be_solved; - for (auto node = 0; node < graph.getVertices(); node++) { - // If a node doesn't have any input edges, then that node will - // definately not result in a cycle and can be visited safely. - if (!indegree[node]) { - can_be_solved.emplace(node); - } - } - - // Vertices that need to be traversed. - auto remain = graph.getVertices(); - // While there are safe nodes that we can visit. - while (!can_be_solved.empty()) { - auto front = can_be_solved.front(); - // Visit the node. - can_be_solved.pop(); - // Decrease number of nodes that need to be traversed. - remain--; - - // Visit all the children of the visited node. - if (auto it = graphAjdList.find(front); it != graphAjdList.end()) { - for (auto child : it->second) { - // Check if we can visited the node safely. - if (--indegree[child] == 0) { - // if node can be visited safely, then add that node to - // the visit queue. - can_be_solved.emplace(child); - } - } - } - } - - // If there are still nodes that we can't visit, then it means that - // there is a cycle and return true, else return false. - return !(remain == 0); - } -}; - -/** - * Main function. - */ -int main() { - // Instantiate the graph. - Graph g(7, std::vector{{0, 1}, {1, 2}, {2, 0}, {2, 5}, {3, 5}}); - // Check for cycle using BFS method. - std::cout << CycleCheck::isCyclicBFS(g) << '\n'; - - // Check for cycle using DFS method. - std::cout << CycleCheck::isCyclicDFS(g) << '\n'; - return 0; + } + std::cout<<"0"; + return 0; +} + +int main() { + size_t n, m; + std::cin >> n >> m; + vector > adj(n, vector()); + for (size_t i = 0; i < m; i++) { + int x, y; + std::cin >> x >> y; + adj[x - 1].push_back(y - 1); + } + acyclic(adj,n); } diff --git a/graph/dfs.cpp b/graph/dfs.cpp index 2d38c8725..f79179045 100644 --- a/graph/dfs.cpp +++ b/graph/dfs.cpp @@ -1,26 +1,133 @@ +/** + * + * \file + * \brief [Depth First Search Algorithm + * (Depth First Search)](https://en.wikipedia.org/wiki/Depth-first_search) + * + * \author [Ayaan Khan](http://github.com/ayaankhan98) + * + * \details + * Depth First Search also quoted as DFS is a Graph Traversal Algorithm. + * Time Complexity O(|V| + |E|) where V is number of vertices and E + * is number of edges in graph. + * + * Application of Depth First Search are + * + * 1. Finding connected components + * 2. Finding 2-(edge or vertex)-connected components. + * 3. Finding 3-(edge or vertex)-connected components. + * 4. Finding the bridges of a graph. + * 5. Generating words in order to plot the limit set of a group. + * 6. Finding strongly connected components. + * + * And there are many more... + * + *

Working

+ * 1. Mark all vertices as unvisited first + * 2. start exploring from some starting vertex. + * + * While exploring vertex we mark the vertex as visited + * and start exploring the vertices connected to this + * vertex in recursive way. + * + */ + +#include #include -using namespace std; -int v = 4; -void DFSUtil_(int graph[4][4], bool visited[], int s) { - visited[s] = true; - cout << s << " "; - for (int i = 0; i < v; i++) { - if (graph[s][i] == 1 && visited[i] == false) { - DFSUtil_(graph, visited, i); +#include + +/** + * + * \namespace graph + * \brief Graph Algorithms + * + */ +namespace graph { +/** + * \brief + * Adds and edge between two vertices of graph say u and v in this + * case. + * + * @param adj Adjacency list representation of graph + * @param u first vertex + * @param v second vertex + * + */ +void addEdge(std::vector> *adj, size_t u, size_t v) { + /** + * + * Here we are considering undirected graph that's the + * reason we are adding v to the adjacency list representation of u + * and also adding u to the adjacency list representation of v + * + */ + (*adj)[u - 1].push_back(v - 1); + (*adj)[v - 1].push_back(u - 1); +} + +/** + * + * \brief + * Explores the given vertex, exploring a vertex means traversing + * over all the vertices which are connected to the vertex that is + * currently being explored. + * + * @param adj garph + * @param v vertex to be explored + * @param visited already visited vertices + * + */ +void explore(const std::vector> &adj, size_t v, + std::vector *visited) { + std::cout << v + 1 << " "; + (*visited)[v] = true; + for (auto x : adj[v]) { + if (!(*visited)[x]) { + explore(adj, x, visited); } } } -void DFS_(int graph[4][4], int s) { - bool visited[v]; - memset(visited, 0, sizeof(visited)); - DFSUtil_(graph, visited, s); -} +/** + * \brief + * initiates depth first search algorithm. + * + * @param adj adjacency list of graph + * @param start vertex from where DFS starts traversing. + * + */ +void depth_first_search(const std::vector> &adj, + size_t start) { + size_t vertices = adj.size(); + std::vector visited(vertices, false); + explore(adj, start, &visited); +} +} // namespace graph + +/** Main function */ int main() { - int graph[4][4] = {{0, 1, 1, 0}, {0, 0, 1, 0}, {1, 0, 0, 1}, {0, 0, 0, 1}}; - cout << "DFS: "; - DFS_(graph, 2); - cout << endl; + size_t vertices, edges; + std::cout << "Enter the Vertices : "; + std::cin >> vertices; + std::cout << "Enter the Edges : "; + std::cin >> edges; + + /// creating graph + std::vector> adj(vertices, std::vector()); + + /// taking input for edges + std::cout << "Enter the vertices which have edges between them : " + << std::endl; + while (edges--) { + size_t u, v; + std::cin >> u >> v; + graph::addEdge(&adj, u, v); + } + + /// running depth first search over graph + graph::depth_first_search(adj, 2); + + std::cout << std::endl; return 0; } \ No newline at end of file diff --git a/graph/dijkstra.cpp b/graph/dijkstra.cpp index 90fb0ec4f..ac269de18 100644 --- a/graph/dijkstra.cpp +++ b/graph/dijkstra.cpp @@ -39,31 +39,31 @@ constexpr int64_t INF = std::numeric_limits::max(); */ namespace graph { -/** - * @brief Function that add edge between two nodes or vertices of graph - * - * @param u any node or vertex of graph - * @param v any node or vertex of graph - */ -void addEdge(std::vector>> *adj, int u, int v, - int w) { + /** + * @brief Function that add edge between two nodes or vertices of graph + * + * @param u any node or vertex of graph + * @param v any node or vertex of graph + */ + void addEdge(std::vector>> *adj, int u, int v, + int w) { (*adj)[u - 1].push_back(std::make_pair(v - 1, w)); // (*adj)[v - 1].push_back(std::make_pair(u - 1, w)); -} + } -/** - * @brief Function runs the dijkstra algorithm for some source vertex and - * target vertex in the graph and returns the shortest distance of target - * from the source. - * - * @param adj input graph - * @param s source vertex - * @param t target vertex - * - * @return shortest distance if target is reachable from source else -1 in - * case if target is not reachable from source. - */ -int dijkstra(std::vector>> *adj, int s, int t) { + /** + * @brief Function runs the dijkstra algorithm for some source vertex and + * target vertex in the graph and returns the shortest distance of target + * from the source. + * + * @param adj input graph + * @param s source vertex + * @param t target vertex + * + * @return shortest distance if target is reachable from source else -1 in + * case if target is not reachable from source. + */ + int dijkstra(std::vector>> *adj, int s, int t) { /// n denotes the number of vertices in graph int n = adj->size(); @@ -74,7 +74,7 @@ int dijkstra(std::vector>> *adj, int s, int t) { /// first element of pair contains the distance /// second element of pair contains the vertex std::priority_queue, std::vector>, - std::greater<>> + std::greater>> pq; /// pushing the source vertex 's' with 0 distance in min heap @@ -84,97 +84,97 @@ int dijkstra(std::vector>> *adj, int s, int t) { dist[s] = 0; while (!pq.empty()) { - /// second element of pair denotes the node / vertex - int currentNode = pq.top().second; + /// second element of pair denotes the node / vertex + int currentNode = pq.top().second; - /// first element of pair denotes the distance - int currentDist = pq.top().first; + /// first element of pair denotes the distance + int currentDist = pq.top().first; - pq.pop(); + pq.pop(); - /// for all the reachable vertex from the currently exploring vertex - /// we will try to minimize the distance - for (std::pair edge : (*adj)[currentNode]) { - /// minimizing distances - if (currentDist + edge.second < dist[edge.first]) { - dist[edge.first] = currentDist + edge.second; - pq.push(std::make_pair(dist[edge.first], edge.first)); - } + /// for all the reachable vertex from the currently exploring vertex + /// we will try to minimize the distance + for (std::pair edge : (*adj)[currentNode]) { + /// minimizing distances + if (currentDist + edge.second < dist[edge.first]) { + dist[edge.first] = currentDist + edge.second; + pq.push(std::make_pair(dist[edge.first], edge.first)); } + } } if (dist[t] != INF) { - return dist[t]; + return dist[t]; } return -1; -} + } } // namespace graph /** Function to test the Algorithm */ void tests() { - std::cout << "Initiatinig Predefined Tests..." << std::endl; - std::cout << "Initiating Test 1..." << std::endl; - std::vector>> adj1( - 4, std::vector>()); - graph::addEdge(&adj1, 1, 2, 1); - graph::addEdge(&adj1, 4, 1, 2); - graph::addEdge(&adj1, 2, 3, 2); - graph::addEdge(&adj1, 1, 3, 5); + std::cout << "Initiatinig Predefined Tests..." << std::endl; + std::cout << "Initiating Test 1..." << std::endl; + std::vector>> adj1( + 4, std::vector>()); + graph::addEdge(&adj1, 1, 2, 1); + graph::addEdge(&adj1, 4, 1, 2); + graph::addEdge(&adj1, 2, 3, 2); + graph::addEdge(&adj1, 1, 3, 5); - int s = 1, t = 3; - assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3); - std::cout << "Test 1 Passed..." << std::endl; + int s = 1, t = 3; + assert(graph::dijkstra(&adj1, s - 1, t - 1) == 3); + std::cout << "Test 1 Passed..." << std::endl; - s = 4, t = 3; - std::cout << "Initiating Test 2..." << std::endl; - assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5); - std::cout << "Test 2 Passed..." << std::endl; + s = 4, t = 3; + std::cout << "Initiating Test 2..." << std::endl; + assert(graph::dijkstra(&adj1, s - 1, t - 1) == 5); + std::cout << "Test 2 Passed..." << std::endl; - std::vector>> adj2( - 5, std::vector>()); - graph::addEdge(&adj2, 1, 2, 4); - graph::addEdge(&adj2, 1, 3, 2); - graph::addEdge(&adj2, 2, 3, 2); - graph::addEdge(&adj2, 3, 2, 1); - graph::addEdge(&adj2, 2, 4, 2); - graph::addEdge(&adj2, 3, 5, 4); - graph::addEdge(&adj2, 5, 4, 1); - graph::addEdge(&adj2, 2, 5, 3); - graph::addEdge(&adj2, 3, 4, 4); + std::vector>> adj2( + 5, std::vector>()); + graph::addEdge(&adj2, 1, 2, 4); + graph::addEdge(&adj2, 1, 3, 2); + graph::addEdge(&adj2, 2, 3, 2); + graph::addEdge(&adj2, 3, 2, 1); + graph::addEdge(&adj2, 2, 4, 2); + graph::addEdge(&adj2, 3, 5, 4); + graph::addEdge(&adj2, 5, 4, 1); + graph::addEdge(&adj2, 2, 5, 3); + graph::addEdge(&adj2, 3, 4, 4); - s = 1, t = 5; - std::cout << "Initiating Test 3..." << std::endl; - assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6); - std::cout << "Test 3 Passed..." << std::endl; - std::cout << "All Test Passed..." << std::endl << std::endl; + s = 1, t = 5; + std::cout << "Initiating Test 3..." << std::endl; + assert(graph::dijkstra(&adj2, s - 1, t - 1) == 6); + std::cout << "Test 3 Passed..." << std::endl; + std::cout << "All Test Passed..." << std::endl << std::endl; } /** Main function */ int main() { - // running predefined tests - tests(); + // running predefined tests + tests(); - int vertices = int(), edges = int(); - std::cout << "Enter the number of vertices : "; - std::cin >> vertices; - std::cout << "Enter the number of edges : "; - std::cin >> edges; + int vertices = int(), edges = int(); + std::cout << "Enter the number of vertices : "; + std::cin >> vertices; + std::cout << "Enter the number of edges : "; + std::cin >> edges; - std::vector>> adj( - vertices, std::vector>()); + std::vector>> adj( + vertices, std::vector>()); - int u = int(), v = int(), w = int(); - while (edges--) { - std::cin >> u >> v >> w; - graph::addEdge(&adj, u, v, w); - } + int u = int(), v = int(), w = int(); + while (edges--) { + std::cin >> u >> v >> w; + graph::addEdge(&adj, u, v, w); + } - int s = int(), t = int(); - std::cin >> s >> t; - int dist = graph::dijkstra(&adj, s - 1, t - 1); - if (dist == -1) { - std::cout << "Target not reachable from source" << std::endl; - } else { - std::cout << "Shortest Path Distance : " << dist << std::endl; - } - return 0; + int s = int(), t = int(); + std::cin >> s >> t; + int dist = graph::dijkstra(&adj, s - 1, t - 1); + if (dist == -1) { + std::cout << "Target not reachable from source" << std::endl; + } else { + std::cout << "Shortest Path Distance : " << dist << std::endl; + } + return 0; } diff --git a/graph/kosaraju.cpp b/graph/kosaraju.cpp index 00c9d7ca0..a9ef121aa 100644 --- a/graph/kosaraju.cpp +++ b/graph/kosaraju.cpp @@ -4,8 +4,8 @@ #include #include +#include -using namespace std; /** * Iterative function/method to print graph: @@ -13,13 +13,13 @@ using namespace std; * @param V : vertices * @return void **/ -void print(vector a[], int V) { +void print(std::vector a[], int V) { for (int i = 0; i < V; i++) { if (!a[i].empty()) - cout << "i=" << i << "-->"; - for (int j = 0; j < a[i].size(); j++) cout << a[i][j] << " "; + std::cout << "i=" << i << "-->"; + for (int j = 0; j < a[i].size(); j++) std::cout << a[i][j] << " "; if (!a[i].empty()) - cout << endl; + std::cout << std::endl; } } @@ -31,7 +31,7 @@ void print(vector a[], int V) { * @param adj[] : array of vectors to represent graph * @return void **/ -void push_vertex(int v, stack &st, bool vis[], vector adj[]) { +void push_vertex(int v, std::stack &st, bool vis[], std::vector adj[]) { vis[v] = true; for (auto i = adj[v].begin(); i != adj[v].end(); i++) { if (vis[*i] == false) @@ -47,7 +47,7 @@ void push_vertex(int v, stack &st, bool vis[], vector adj[]) { * @param grev[] : graph with reversed edges * @return void **/ -void dfs(int v, bool vis[], vector grev[]) { +void dfs(int v, bool vis[], std::vector grev[]) { vis[v] = true; // cout<0)) i.e. it returns the count of (number of) strongly connected components (SCCs) in the graph. (variable 'count_scc' within function) **/ -int kosaraju(int V, vector adj[]) { +int kosaraju(int V, std::vector adj[]) { bool vis[V] = {}; - stack st; + std::stack st; for (int v = 0; v < V; v++) { if (vis[v] == false) push_vertex(v, st, vis, adj); } // making new graph (grev) with reverse edges as in adj[]: - vector grev[V]; + std::vector grev[V]; for (int i = 0; i < V + 1; i++) { for (auto j = adj[i].begin(); j != adj[i].end(); j++) { grev[*j].push_back(i); @@ -102,20 +102,20 @@ int kosaraju(int V, vector adj[]) { // Input your required values: (not hardcoded) int main() { int t; - cin >> t; + std::cin >> t; while (t--) { int a, b; // a->number of nodes, b->directed edges. - cin >> a >> b; + std::cin >> a >> b; int m, n; - vector adj[a + 1]; + std::vector adj[a + 1]; for (int i = 0; i < b; i++) // take total b inputs of 2 vertices each // required to form an edge. { - cin >> m >> n; // take input m,n denoting edge from m->n. + std::cin >> m >> n; // take input m,n denoting edge from m->n. adj[m].push_back(n); } // pass number of nodes and adjacency array as parameters to function: - cout << kosaraju(a, adj) << endl; + std::cout << kosaraju(a, adj) << std::endl; } return 0; } diff --git a/graph/kruskal.cpp b/graph/kruskal.cpp index b7b830668..861b81ae1 100644 --- a/graph/kruskal.cpp +++ b/graph/kruskal.cpp @@ -1,4 +1,6 @@ #include +#include +#include //#include // using namespace boost::multiprecision; const int mx = 1e6 + 5; diff --git a/graph/lca.cpp b/graph/lca.cpp index c05cf7b9b..e69be62fa 100644 --- a/graph/lca.cpp +++ b/graph/lca.cpp @@ -1,7 +1,9 @@ //#include #include - -using namespace std; +#include +#include +#include +#include // Find the lowest common ancestor using binary lifting in O(nlogn) // Zero based indexing // Resource : https://cp-algorithms.com/graph/lca_binary_lifting.html @@ -9,7 +11,7 @@ const int N = 1005; const int LG = log2(N) + 1; struct lca { int n; - vector adj[N]; // Graph + std::vector adj[N]; // Graph int up[LG][N]; // build this table int level[N]; // get the levels of all of them @@ -18,7 +20,7 @@ struct lca { memset(level, 0, sizeof(level)); for (int i = 0; i < n - 1; ++i) { int a, b; - cin >> a >> b; + std::cin >> a >> b; a--; b--; adj[a].push_back(b); @@ -30,15 +32,15 @@ struct lca { } void verify() { for (int i = 0; i < n; ++i) { - cout << i << " : level: " << level[i] << endl; + std::cout << i << " : level: " << level[i] << std::endl; } - cout << endl; + std::cout << std::endl; for (int i = 0; i < LG; ++i) { - cout << "Power:" << i << ": "; + std::cout << "Power:" << i << ": "; for (int j = 0; j < n; ++j) { - cout << up[i][j] << " "; + std::cout << up[i][j] << " "; } - cout << endl; + std::cout << std::endl; } } @@ -65,7 +67,7 @@ struct lca { u--; v--; if (level[v] > level[u]) { - swap(u, v); + std::swap(u, v); } // u is at the bottom. int dist = level[u] - level[v]; diff --git a/graph/topological_sort.cpp b/graph/topological_sort.cpp index 9e6c8917b..e7dd7ab63 100644 --- a/graph/topological_sort.cpp +++ b/graph/topological_sort.cpp @@ -1,12 +1,11 @@ #include #include #include -using namespace std; int n, m; // For number of Vertices (V) and number of edges (E) -vector> G; -vector visited; -vector ans; +std::vector> G; +std::vector visited; +std::vector ans; void dfs(int v) { visited[v] = true; @@ -27,21 +26,21 @@ void topological_sort() { reverse(ans.begin(), ans.end()); } int main() { - cout << "Enter the number of vertices and the number of directed edges\n"; - cin >> n >> m; + std::cout << "Enter the number of vertices and the number of directed edges\n"; + std::cin >> n >> m; int x, y; - G.resize(n, vector()); + G.resize(n, std::vector()); for (int i = 0; i < n; ++i) { - cin >> x >> y; + std::cin >> x >> y; x--, y--; // to convert 1-indexed to 0-indexed G[x].push_back(y); } topological_sort(); - cout << "Topological Order : \n"; + std::cout << "Topological Order : \n"; for (int v : ans) { - cout << v + 1 + std::cout << v + 1 << ' '; // converting zero based indexing back to one based. } - cout << '\n'; + std::cout << '\n'; return 0; } From e2f344c498e27aba17194032d4da5e77b82acdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Sat, 1 Aug 2020 22:55:50 -0700 Subject: [PATCH 12/31] Fix linter warnings in fixgraph branch. --- graph/bfs.cpp | 8 +- .../bridge_finding_with_tarjan_algorithm.cpp | 4 +- graph/cycle_check_directed_graph.cpp | 35 +++--- graph/dfs.cpp | 6 +- graph/kosaraju.cpp | 53 +++++---- graph/kruskal.cpp | 105 +++++------------- graph/lca.cpp | 4 +- graph/topological_sort.cpp | 8 +- 8 files changed, 92 insertions(+), 131 deletions(-) diff --git a/graph/bfs.cpp b/graph/bfs.cpp index 31f9c0770..9e66f3ff2 100644 --- a/graph/bfs.cpp +++ b/graph/bfs.cpp @@ -91,7 +91,7 @@ std::vector beadth_first_search(const std::vector> &adj, std::vector result; /// vector to keep track of visited vertices - std::vector visited(vertices, 0); + std::vector visited(vertices, false); std::queue tracker; /// marking the start vertex as visited @@ -172,7 +172,7 @@ int main() { /// running predefined test cases tests(); - size_t vertices, edges; + size_t vertices = 0, edges = 0; std::cout << "Enter the number of vertices : "; std::cin >> vertices; std::cout << "Enter the number of edges : "; @@ -185,7 +185,7 @@ int main() { std::cout << "Enter vertices in pair which have edges between them : " << std::endl; while (edges--) { - int u, v; + int u = 0, v = 0; std::cin >> u >> v; graph::addEdge(&adj, u, v); } @@ -193,4 +193,4 @@ int main() { /// running Breadth First Search Algorithm on the graph graph::beadth_first_search(adj, 0); return 0; -} \ No newline at end of file +} diff --git a/graph/bridge_finding_with_tarjan_algorithm.cpp b/graph/bridge_finding_with_tarjan_algorithm.cpp index 2b54e1b96..5f1b5796a 100644 --- a/graph/bridge_finding_with_tarjan_algorithm.cpp +++ b/graph/bridge_finding_with_tarjan_algorithm.cpp @@ -15,7 +15,7 @@ using std::vector; class Solution { vector> graph; vector in_time, out_time; - int timer; + int timer = 0; vector> bridge; vector visited; void dfs(int current_node, int parent) { @@ -51,7 +51,7 @@ class Solution { return bridge; } }; -int main(void) { +int main() { Solution s1; int number_of_node = 5; vector> node; diff --git a/graph/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp index c991730c0..cb36a13c8 100644 --- a/graph/cycle_check_directed_graph.cpp +++ b/graph/cycle_check_directed_graph.cpp @@ -1,39 +1,44 @@ #include #include -#include +#include using std::vector; using std::pair; -void explore(int i, vector> &adj, int *state) +void explore(int i, const vector> &adj, std::vector *state) { - state[i] = 1; - for(auto it2 : adj[i]) + (*state)[i] = 1; + for (const auto it2 : adj[i]) { - if (state[it2] == 0) + if ((*state)[it2] == 0) { - explore(it2, adj,state); + explore(it2, adj, state); } - if (state[it2] == 1) + if ((*state)[it2] == 1) { std::cout<<"1"; exit(0); } } - state[i] = 2; + (*state)[i] = 2; }; -int acyclic(vector > &adj,size_t n) { +int acyclic(const vector > &adj, size_t n) { //write your code here - int state[n]; // permitted states are 0 1 and 2 + // permitted states are 0 1 and 2 + std::vector state(n, 0); // mark the states of all vertices initially to 0 - for(int i=0;i > &adj,size_t n) { } int main() { - size_t n, m; + size_t n = 0, m = 0; std::cin >> n >> m; vector > adj(n, vector()); for (size_t i = 0; i < m; i++) { - int x, y; + int x = 0, y = 0; std::cin >> x >> y; adj[x - 1].push_back(y - 1); } diff --git a/graph/dfs.cpp b/graph/dfs.cpp index f79179045..e3f4e7ece 100644 --- a/graph/dfs.cpp +++ b/graph/dfs.cpp @@ -107,7 +107,7 @@ void depth_first_search(const std::vector> &adj, /** Main function */ int main() { - size_t vertices, edges; + size_t vertices = 0, edges = 0; std::cout << "Enter the Vertices : "; std::cin >> vertices; std::cout << "Enter the Edges : "; @@ -120,7 +120,7 @@ int main() { std::cout << "Enter the vertices which have edges between them : " << std::endl; while (edges--) { - size_t u, v; + size_t u = 0, v = 0; std::cin >> u >> v; graph::addEdge(&adj, u, v); } @@ -130,4 +130,4 @@ int main() { std::cout << std::endl; return 0; -} \ No newline at end of file +} diff --git a/graph/kosaraju.cpp b/graph/kosaraju.cpp index a9ef121aa..751ace56f 100644 --- a/graph/kosaraju.cpp +++ b/graph/kosaraju.cpp @@ -13,13 +13,17 @@ * @param V : vertices * @return void **/ -void print(std::vector a[], int V) { +void print(const std::vector< std::vector > &a, int V) { for (int i = 0; i < V; i++) { - if (!a[i].empty()) + if (!a[i].empty()) { std::cout << "i=" << i << "-->"; - for (int j = 0; j < a[i].size(); j++) std::cout << a[i][j] << " "; - if (!a[i].empty()) + } + for (int j : a[i]) { + std::cout << j << " "; + } + if (!a[i].empty()) { std::cout << std::endl; + } } } @@ -27,32 +31,34 @@ void print(std::vector a[], int V) { * //Recursive function/method to push vertices into stack passed as parameter: * @param v : vertices * @param &st : stack passed by reference - * @param vis[] : array to keep track of visited nodes (boolean type) + * @param &vis : array to keep track of visited nodes (boolean type) * @param adj[] : array of vectors to represent graph * @return void **/ -void push_vertex(int v, std::stack &st, bool vis[], std::vector adj[]) { - vis[v] = true; +void push_vertex(int v, std::stack *st, std::vector *vis, const std::vector< std::vector > &adj) { + (*vis)[v] = true; for (auto i = adj[v].begin(); i != adj[v].end(); i++) { - if (vis[*i] == false) + if ((*vis)[*i] == false) { push_vertex(*i, st, vis, adj); + } } - st.push(v); + st->push(v); } /** * //Recursive function/method to implement depth first traversal(dfs): * @param v : vertices - * @param vis[] : array to keep track of visited nodes (boolean type) + * @param vis : array to keep track of visited nodes (boolean type) * @param grev[] : graph with reversed edges * @return void **/ -void dfs(int v, bool vis[], std::vector grev[]) { - vis[v] = true; +void dfs(int v, std::vector *vis, const std::vector< std::vector > &grev) { + (*vis)[v] = true; // cout<0)) i.e. it returns the count of (number of) strongly connected components (SCCs) in the graph. (variable 'count_scc' within function) **/ -int kosaraju(int V, std::vector adj[]) { - bool vis[V] = {}; +int kosaraju(int V, const std::vector< std::vector > &adj) { + std::vector vis(V, false); std::stack st; for (int v = 0; v < V; v++) { - if (vis[v] == false) - push_vertex(v, st, vis, adj); + if (vis[v] == false) { + push_vertex(v, &st, &vis, adj); + } } // making new graph (grev) with reverse edges as in adj[]: - std::vector grev[V]; + std::vector< std::vector > grev(V); for (int i = 0; i < V + 1; i++) { for (auto j = adj[i].begin(); j != adj[i].end(); j++) { grev[*j].push_back(i); @@ -89,7 +96,7 @@ int kosaraju(int V, std::vector adj[]) { int t = st.top(); st.pop(); if (vis[t] == false) { - dfs(t, vis, grev); + dfs(t, &vis, grev); count_scc++; } } @@ -101,13 +108,13 @@ int kosaraju(int V, std::vector adj[]) { // All critical/corner cases have been taken care of. // Input your required values: (not hardcoded) int main() { - int t; + int t = 0; std::cin >> t; while (t--) { - int a, b; // a->number of nodes, b->directed edges. + int a = 0, b = 0; // a->number of nodes, b->directed edges. std::cin >> a >> b; - int m, n; - std::vector adj[a + 1]; + int m = 0, n = 0; + std::vector< std::vector > adj(a + 1); for (int i = 0; i < b; i++) // take total b inputs of 2 vertices each // required to form an edge. { diff --git a/graph/kruskal.cpp b/graph/kruskal.cpp index 861b81ae1..deec717c0 100644 --- a/graph/kruskal.cpp +++ b/graph/kruskal.cpp @@ -1,75 +1,21 @@ #include #include #include +#include //#include // using namespace boost::multiprecision; const int mx = 1e6 + 5; -const long int inf = 2e9; -typedef long long ll; -#define rep(i, n) for (i = 0; i < n; i++) -#define repp(i, a, b) for (i = a; i <= b; i++) -#define pii pair -#define vpii vector -#define vi vector -#define vll vector -#define r(x) scanf("%d", &x) -#define rs(s) scanf("%s", s) -#define gc getchar_unlocked -#define pc putchar_unlocked -#define mp make_pair -#define pb push_back -#define lb lower_bound -#define ub upper_bound -#define endl "\n" -#define fast \ - ios_base::sync_with_stdio(false); \ - cin.tie(NULL); \ - cout.tie(NULL); -using namespace std; -void in(int &x) { - register int c = gc(); - x = 0; - int neg = 0; - for (; ((c < 48 || c > 57) && c != '-'); c = gc()) - ; - if (c == '-') { - neg = 1; - c = gc(); - } - for (; c > 47 && c < 58; c = gc()) { - x = (x << 1) + (x << 3) + c - 48; - } - if (neg) - x = -x; -} -void out(int n) { - int N = n, rev, count = 0; - rev = N; - if (N == 0) { - pc('0'); - return; - } - while ((rev % 10) == 0) { - count++; - rev /= 10; - } - rev = 0; - while (N != 0) { - rev = (rev << 3) + (rev << 1) + N % 10; - N /= 10; - } - while (rev != 0) { - pc(rev % 10 + '0'); - rev /= 10; - } - while (count--) pc('0'); -} -ll parent[mx], arr[mx], node, edge; -vector>> v; +typedef int64_t ll; + +std::array parent, arr; +ll node, edge; +std::vector>> v; void initial() { - int i; - rep(i, node + edge) parent[i] = i; + for (int i = 0; i < node + edge; ++i) { + parent[i] = i; + } } + int root(int i) { while (parent[i] != i) { parent[i] = parent[parent[i]]; @@ -77,16 +23,18 @@ int root(int i) { } return i; } + void join(int x, int y) { int root_x = root(x); // Disjoint set union by rank int root_y = root(y); parent[root_x] = root_y; } + ll kruskal() { - ll mincost = 0, i, x, y; - rep(i, edge) { - x = v[i].second.first; - y = v[i].second.second; + ll mincost = 0; + for (int i = 0; i < edge; ++i) { + ll x = v[i].second.first; + ll y = v[i].second.second; if (root(x) != root(y)) { mincost += v[i].first; join(x, y); @@ -94,23 +42,22 @@ ll kruskal() { } return mincost; } + int main() { - fast; - while (1) { - int i, j, from, to, cost, totalcost = 0; - cin >> node >> edge; // Enter the nodes and edges - if (node == 0 && edge == 0) + while (true) { + int from = 0, to = 0, cost = 0, totalcost = 0; + std::cin >> node >> edge; // Enter the nodes and edges + if (node == 0 && edge == 0) { break; // Enter 0 0 to break out + } initial(); // Initialise the parent array - rep(i, edge) { - cin >> from >> to >> cost; - v.pb(mp(cost, mp(from, to))); + for (int i = 0; i < edge; ++i) { + std::cin >> from >> to >> cost; + v.emplace_back(make_pair(cost, std::make_pair(from, to))); totalcost += cost; } sort(v.begin(), v.end()); - // rep(i,v.size()) - // cout< adj[N]; // Graph diff --git a/graph/topological_sort.cpp b/graph/topological_sort.cpp index e7dd7ab63..f77780cdc 100644 --- a/graph/topological_sort.cpp +++ b/graph/topological_sort.cpp @@ -10,8 +10,9 @@ std::vector ans; void dfs(int v) { visited[v] = true; for (int u : G[v]) { - if (!visited[u]) + if (!visited[u]) { dfs(u); + } } ans.push_back(v); } @@ -20,15 +21,16 @@ void topological_sort() { visited.assign(n, false); ans.clear(); for (int i = 0; i < n; ++i) { - if (!visited[i]) + if (!visited[i]) { dfs(i); + } } reverse(ans.begin(), ans.end()); } int main() { std::cout << "Enter the number of vertices and the number of directed edges\n"; std::cin >> n >> m; - int x, y; + int x = 0, y = 0; G.resize(n, std::vector()); for (int i = 0; i < n; ++i) { std::cin >> x >> y; From 1c5f229b3c2c11a5db7f77566227576f63f25163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Sun, 2 Aug 2020 23:45:56 -0700 Subject: [PATCH 13/31] Refactor lowest common ancestor --- graph/lca.cpp | 101 ------------- graph/lowest_common_ancestor.cpp | 252 +++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 101 deletions(-) delete mode 100644 graph/lca.cpp create mode 100644 graph/lowest_common_ancestor.cpp diff --git a/graph/lca.cpp b/graph/lca.cpp deleted file mode 100644 index 22c133016..000000000 --- a/graph/lca.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//#include -#include -#include -#include -#include -#include -// Find the lowest common ancestor using binary lifting in O(nlogn) -// Zero based indexing -// Resource : https://cp-algorithms.com/graph/lca_binary_lifting.html -constexpr int N = 1005; -constexpr int LG = 20; -struct lca { - int n; - std::vector adj[N]; // Graph - int up[LG][N]; // build this table - int level[N]; // get the levels of all of them - - lca(int n_) : n(n_) { - memset(up, -1, sizeof(up)); - memset(level, 0, sizeof(level)); - for (int i = 0; i < n - 1; ++i) { - int a, b; - std::cin >> a >> b; - a--; - b--; - adj[a].push_back(b); - adj[b].push_back(a); - } - level[0] = 0; - dfs(0, -1); - build(); - } - void verify() { - for (int i = 0; i < n; ++i) { - std::cout << i << " : level: " << level[i] << std::endl; - } - std::cout << std::endl; - for (int i = 0; i < LG; ++i) { - std::cout << "Power:" << i << ": "; - for (int j = 0; j < n; ++j) { - std::cout << up[i][j] << " "; - } - std::cout << std::endl; - } - } - - void build() { - for (int i = 1; i < LG; ++i) { - for (int j = 0; j < n; ++j) { - if (up[i - 1][j] != -1) { - up[i][j] = up[i - 1][up[i - 1][j]]; - } - } - } - } - - void dfs(int node, int par) { - up[0][node] = par; - for (auto i : adj[node]) { - if (i != par) { - level[i] = level[node] + 1; - dfs(i, node); - } - } - } - int query(int u, int v) { - u--; - v--; - if (level[v] > level[u]) { - std::swap(u, v); - } - // u is at the bottom. - int dist = level[u] - level[v]; - // Go up this much distance - for (int i = LG - 1; i >= 0; --i) { - if (dist & (1 << i)) { - u = up[i][u]; - } - } - if (u == v) { - return u; - } - assert(level[u] == level[v]); - for (int i = LG - 1; i >= 0; --i) { - if (up[i][u] != up[i][v]) { - u = up[i][u]; - v = up[i][v]; - } - } - assert(up[0][u] == up[0][v]); - return up[0][u]; - } -}; - -int main() { - int n; // number of nodes in the tree. - lca l(n); // will take the input in the format given - // n-1 edges of the form - // a b - // Use verify function to see. -} diff --git a/graph/lowest_common_ancestor.cpp b/graph/lowest_common_ancestor.cpp new file mode 100644 index 000000000..994a574b4 --- /dev/null +++ b/graph/lowest_common_ancestor.cpp @@ -0,0 +1,252 @@ +/** + * + * \file + * + * \brief Data structure for finding the lowest common ancestor + * of two vertices in a rooted tree using binary lifting. + * + * \details + * Algorithm: https://cp-algorithms.com/graph/lca_binary_lifting.html + * + * Complexity: + * - Precomputation: \f$O(N \log N)\f$ where \f$N\f$ is the number of vertices in the tree + * - Query: \f$O(\log N)\f$ + * - Space: \f$O(N \log N)\f$ + * + * Example: + *
Tree: + *
+ *             _  3  _
+ *          /     |     \
+ *        1       6       4
+ *      / |     /   \       \
+ *    7   5   2       8       0
+ *            |
+ *            9
+ * 
+ * + *
lowest_common_ancestor(7, 4) = 3 + *
lowest_common_ancestor(9, 6) = 6 + *
lowest_common_ancestor(0, 0) = 0 + *
lowest_common_ancestor(8, 2) = 6 + * + * The query is symmetrical, therefore + * lowest_common_ancestor(x, y) = lowest_common_ancestor(y, x) + */ + +#include +#include +#include +#include +#include + +/** + * Class for representing a graph as an adjacency list. + * Its vertices are indexed 0, 1, ..., N - 1. + */ +class Graph { + public: + /** + * \brief Populate the adjacency list for each vertex in the graph. + * Assumes that evey edge is a pair of valid vertex indices. + * + * @param N number of vertices in the graph + * @param undirected_edges list of graph's undirected edges + */ + Graph(size_t N, const std::vector< std::pair > &undirected_edges) { + neighbors.resize(N); + for (auto &edge : undirected_edges) { + neighbors[edge.first].push_back(edge.second); + neighbors[edge.second].push_back(edge.first); + } + } + + /** + * Function to get the number of vertices in the graph + * @return the number of vertices in the graph. + */ + int number_of_vertices() const { + return neighbors.size(); + } + + /** \brief for each vertex it stores a list indicies of its neighbors */ + std::vector< std::vector > neighbors; +}; + +/** + * Representation of a rooted tree. For every vertex its parent is precalculated. + */ +class RootedTree : public Graph { + public: + /** + * \brief Constructs the tree by calculating parent for every vertex. + * Assumes a valid description of a tree is provided. + * + * @param undirected_edges list of graph's undirected edges + * @param root_ index of the root vertex + */ + RootedTree(const std::vector< std::pair > &undirected_edges, int root_) + : Graph(undirected_edges.size() + 1, undirected_edges), root(root_) { + populate_parents(); + } + + /** + * \brief Stores parent of every vertex and for root its own index. + * The root is technically not its own parent, but it's very practical + * for the lowest common ancestor algorithm. + */ + std::vector parent; + /** \brief Stores the distance from the root. */ + std::vector level; + /** \brief Index of the root vertex. */ + int root; + + protected: + /** + * \brief Calculate the parents for all the vertices in the tree. + * Implements the breadth first search algorithm starting from the root + * vertex searching the entire tree and labeling parents for all vertices. + * @returns none + */ + void populate_parents() { + // Initialize the vector with -1 which indicates the vertex + // wasn't yet visited. + parent = std::vector(number_of_vertices(), -1); + level = std::vector(number_of_vertices()); + parent[root] = root; + level[root] = 0; + std::queue queue_of_vertices; + queue_of_vertices.push(root); + while (!queue_of_vertices.empty()) { + int vertex = queue_of_vertices.front(); + queue_of_vertices.pop(); + for (int neighbor : neighbors[vertex]) { + // As long as the vertex was not yet visited. + if (parent[neighbor] == -1) { + parent[neighbor] = vertex; + level[neighbor] = level[vertex] + 1; + queue_of_vertices.push(neighbor); + } + } + } + } + +}; + +/** + * A structure that holds a rooted tree and allow for effecient + * queries of the lowest common ancestor of two given vertices in the tree. + */ +class LowestCommonAncestor { + public: + /** + * \brief Stores the tree and precomputs "up lifts". + * @param tree_ rooted tree. + */ + explicit LowestCommonAncestor(const RootedTree& tree_) : tree(tree_) { + populate_up(); + } + + /** + * \brief Query the structure to find the lowest common ancestor. + * Assumes that the provided numbers are valid indices of vertices. + * Iterativelly modifies ("lifts") u an v until it finnds their lowest + * common ancestor. + * @param u index of one of the queried vertex + * @param v index of the other queried vertex + * @return index of the vertex which is the lowet common ancestor of u and v + */ + int lowest_common_ancestor(int u, int v) const { + // Ensure u is the deeper (higher level) of the two vertices + if (tree.level[v] > tree.level[u]) { + std::swap(u, v); + } + + // "Lift" u to the same level as v. + int level_diff = tree.level[u] - tree.level[v]; + for (int i = 0; (1 << i) <= level_diff; ++i) { + if (level_diff & (1 << i)) { + u = up[u][i]; + } + } + assert(tree.level[u] == tree.level[v]); + + if (u == v) { + return u; + } + + // "Lift" u and v to their 2^i th ancestor if they are different + for (int i = static_cast(up[u].size()) - 1; i >= 0; --i) { + if (up[u][i] != up[v][i]) { + u = up[u][i]; + v = up[v][i]; + } + } + + // As we regressed u an v such that they cannot further be lifted so + // that their ancestor would be different, the only logical + // consequence is that their parent is the sought answer. + assert(up[u][0] == up[v][0]); + return up[u][0]; + } + + /* \brief reference to the rooted tree this structure allows to query */ + const RootedTree& tree; + /** + * \brief for every vertex stores a list of its ancestors by powers of two + * For each vertex, the first element of the corresponding list contains + * the index of its parent. The i-th element of the list is an index of + * the (2^i)-th ancestor of the vertex. + */ + std::vector< std::vector > up; + + protected: + /** + * Populate the "up" structure. See above. + */ + void populate_up() { + up.resize(tree.number_of_vertices()); + for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) { + up[vertex].push_back(tree.parent[vertex]); + } + for (int level = 0; (1 << level) < tree.number_of_vertices(); ++level) { + for (int vertex = 0; vertex < tree.number_of_vertices(); ++vertex) { + // up[vertex][level + 1] = 2^(level + 1) th ancestor of vertex = + // = 2^level th ancestor of 2^level th ancestor of vertex = + // = 2^level th ancestor of up[vertex][level] + up[vertex].push_back(up[up[vertex][level]][level]); + } + } + } +}; + +/** + * Unit tests + * @rerturns none + */ +void tests() { + /** + * _ 3 _ + * / | \ + * 1 6 4 + * / | / \ \ + * 7 5 2 8 0 + * | + * 9 + */ + std::vector< std::pair > edges = { + {7, 1}, {1, 5}, {1, 3}, {3, 6}, {6, 2}, {2, 9}, {6, 8}, {4, 3}, {0, 4} + }; + RootedTree t(edges, 3); + LowestCommonAncestor lca(t); + assert(lca.lowest_common_ancestor(7, 4) == 3); + assert(lca.lowest_common_ancestor(9, 6) == 6); + assert(lca.lowest_common_ancestor(0, 0) == 0); + assert(lca.lowest_common_ancestor(8, 2) == 6); +} + +/** Main function */ +int main() { + tests(); + return 0; +} From 0c10e6fee5eb1dc3b9a6adc1172980d4f3f352c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 01:32:48 -0700 Subject: [PATCH 14/31] Fix linter for topological_sort_by_kahns_algo --- graph/topological_sort_by_kahns_algo.cpp | 41 ++++++++++++------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/graph/topological_sort_by_kahns_algo.cpp b/graph/topological_sort_by_kahns_algo.cpp index 57ee01b23..c29c0fc2d 100644 --- a/graph/topological_sort_by_kahns_algo.cpp +++ b/graph/topological_sort_by_kahns_algo.cpp @@ -1,19 +1,20 @@ -#include -#include +#include +#include #include #include #include -int *topoSortKahn(int N, std::vector adj[]); +std::vector topoSortKahn(int N, const std::vector< std::vector > &adj); int main() { - int nodes, edges; + int nodes = 0, edges = 0; std::cin >> edges >> nodes; - if (edges == 0 || nodes == 0) + if (edges == 0 || nodes == 0) { return 0; - int u, v; + } + int u = 0, v = 0; - std::vector graph[nodes]; + std::vector< std::vector > graph(nodes); // create graph // example // 6 6 @@ -24,19 +25,19 @@ int main() { graph[u].push_back(v); } - int *topo = topoSortKahn(nodes, graph); + std::vector topo = topoSortKahn(nodes, graph); // topologically sorted nodes for (int i = 0; i < nodes; i++) { std::cout << topo[i] << " "; } } -int *topoSortKahn(int V, std::vector adj[]) { +std::vector topoSortKahn(int V, const std::vector< std::vector > &adj) { std::vector vis(V + 1, false); std::vector deg(V + 1, 0); for (int i = 0; i < V; i++) { - for (int j = 0; j < adj[i].size(); j++) { - deg[adj[i][j]]++; + for (int j : adj[i]) { + deg[j]++; } } std::queue q; @@ -46,20 +47,18 @@ int *topoSortKahn(int V, std::vector adj[]) { vis[i] = true; } } - int *arr = new int[V + 1]; - memset(arr, 0, V + 1); + std::vector arr(V + 1, 0); int count = 0; while (!q.empty()) { int cur = q.front(); q.pop(); - arr[count] = cur; - count++; - for (int i = 0; i < adj[cur].size(); i++) { - if (!vis[adj[cur][i]]) { - deg[adj[cur][i]]--; - if (deg[adj[cur][i]] == 0) { - q.push(adj[cur][i]); - vis[adj[cur][i]] = true; + arr[count++] = cur; + for (int i : adj[cur]) { + if (!vis[i]) { + deg[i]--; + if (deg[i] == 0) { + q.push(i); + vis[i] = true; } } } From 6be333680f65b387766b65a7694324acdbc4e849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 01:50:47 -0700 Subject: [PATCH 15/31] Remove unused global variable from dfs_with_stack --- graph/dfs_with_stack.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/graph/dfs_with_stack.cpp b/graph/dfs_with_stack.cpp index 193f3f291..5ca1c53b7 100644 --- a/graph/dfs_with_stack.cpp +++ b/graph/dfs_with_stack.cpp @@ -9,8 +9,6 @@ using namespace std; -int checked[999] = {WHITE}; - void dfs(const list lista[], int start) { stack stack; From 891e0dd5ca4e98a7798d3e71d258113d1dd7d23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 02:06:20 -0700 Subject: [PATCH 16/31] Fix linter for dfs_with_stack. --- graph/dfs_with_stack.cpp | 47 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/graph/dfs_with_stack.cpp b/graph/dfs_with_stack.cpp index 5ca1c53b7..2d5752322 100644 --- a/graph/dfs_with_stack.cpp +++ b/graph/dfs_with_stack.cpp @@ -1,32 +1,29 @@ #include #include +#include #include -#define WHITE 0 -#define GREY 1 -#define BLACK 2 -#define INF 99999 - -using namespace std; - -void dfs(const list lista[], int start) { - stack stack; - - int checked[999] = {WHITE}; - - stack.push(start); +constexpr int WHITE = 0; +constexpr int GREY = 1; +constexpr int BLACK = 2; +constexpr int INF = 99999; +void dfs(const std::vector< std::list > &graph, int start) { + std::vector checked(graph.size(), WHITE); checked[start] = GREY; + std::stack stack; + stack.push(start); while (!stack.empty()) { int act = stack.top(); stack.pop(); if (checked[act] == GREY) { - cout << act << ' '; - for (auto it = lista[act].begin(); it != lista[act].end(); ++it) { - stack.push(*it); - if (checked[*it] != BLACK) - checked[*it] = GREY; + std::cout << act << ' '; + for (auto it : graph[act]) { + stack.push(it); + if (checked[it] != BLACK) { + checked[it] = GREY; + } } checked[act] = BLACK; // nodo controllato } @@ -34,16 +31,16 @@ void dfs(const list lista[], int start) { } int main() { - int u, w; - int n; - cin >> n; - list lista[INF]; + int n = 0; + std::cin >> n; + std::vector< std::list > graph(INF); for (int i = 0; i < n; ++i) { - cin >> u >> w; - lista[u].push_back(w); + int u = 0, w = 0; + std::cin >> u >> w; + graph[u].push_back(w); } - dfs(lista, 0); + dfs(graph, 0); return 0; } From d2b70159019827e809ead19c48a30a741140c593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 02:07:59 -0700 Subject: [PATCH 17/31] Remove unused global variable from graph/kruskal. --- graph/kruskal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/kruskal.cpp b/graph/kruskal.cpp index deec717c0..9ee26766f 100644 --- a/graph/kruskal.cpp +++ b/graph/kruskal.cpp @@ -7,7 +7,7 @@ const int mx = 1e6 + 5; typedef int64_t ll; -std::array parent, arr; +std::array parent; ll node, edge; std::vector>> v; void initial() { From ef031dc8f294da2d6c165d7b7898390b23f8fd1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 02:10:00 -0700 Subject: [PATCH 18/31] Rename global variable from v to edges in kruskal. --- graph/kruskal.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/graph/kruskal.cpp b/graph/kruskal.cpp index 9ee26766f..b81a6a104 100644 --- a/graph/kruskal.cpp +++ b/graph/kruskal.cpp @@ -9,7 +9,7 @@ typedef int64_t ll; std::array parent; ll node, edge; -std::vector>> v; +std::vector>> edges; void initial() { for (int i = 0; i < node + edge; ++i) { parent[i] = i; @@ -33,10 +33,10 @@ void join(int x, int y) { ll kruskal() { ll mincost = 0; for (int i = 0; i < edge; ++i) { - ll x = v[i].second.first; - ll y = v[i].second.second; + ll x = edges[i].second.first; + ll y = edges[i].second.second; if (root(x) != root(y)) { - mincost += v[i].first; + mincost += edges[i].first; join(x, y); } } @@ -53,12 +53,12 @@ int main() { initial(); // Initialise the parent array for (int i = 0; i < edge; ++i) { std::cin >> from >> to >> cost; - v.emplace_back(make_pair(cost, std::make_pair(from, to))); + edges.emplace_back(make_pair(cost, std::make_pair(from, to))); totalcost += cost; } - sort(v.begin(), v.end()); + sort(edges.begin(), edges.end()); std::cout << kruskal() << std::endl; - v.clear(); + edges.clear(); } return 0; } From ac26555ec9b5c47848b08003dedc2c2886cff2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 23:40:09 -0700 Subject: [PATCH 19/31] Refactor prim --- graph/prim.cpp | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/graph/prim.cpp b/graph/prim.cpp index 5cc70bd39..c156bf3b8 100644 --- a/graph/prim.cpp +++ b/graph/prim.cpp @@ -3,56 +3,55 @@ #include #include -const int MAX = 1e4 + 5; typedef std::pair PII; -bool marked[MAX]; -std::vector adj[MAX]; - -int prim(int x) { +int prim(int x, const std::vector< std::vector > &graph) { // priority queue to maintain edges with respect to weights std::priority_queue, std::greater > Q; - int y; - int minimumCost = 0; - PII p; + std::vector marked(graph.size(), false); + int minimum_cost = 0; Q.push(std::make_pair(0, x)); while (!Q.empty()) { // Select the edge with minimum weight - p = Q.top(); + PII p = Q.top(); Q.pop(); x = p.second; // Checking for cycle - if (marked[x] == true) + if (marked[x] == true) { continue; - minimumCost += p.first; + } + minimum_cost += p.first; marked[x] = true; - for (int i = 0; i < adj[x].size(); ++i) { - y = adj[x][i].second; - if (marked[y] == false) - Q.push(adj[x][i]); + for (const PII &neighbor : graph[x]) { + int y = neighbor.second; + if (marked[y] == false) { + Q.push(neighbor); + } } } - return minimumCost; + return minimum_cost; } int main() { - int nodes, edges, x, y; - int weight, minimumCost; - + int nodes = 0, edges = 0; std::cin >> nodes >> edges; // number of nodes & edges in graph - if (nodes == 0 || edges == 0) + if (nodes == 0 || edges == 0) { return 0; + } + + std::vector< std::vector > graph(nodes); // Edges with their nodes & weight for (int i = 0; i < edges; ++i) { + int x = 0, y = 0, weight = 0; std::cin >> x >> y >> weight; - adj[x].push_back(std::make_pair(weight, y)); - adj[y].push_back(std::make_pair(weight, x)); + graph[x].push_back(std::make_pair(weight, y)); + graph[y].push_back(std::make_pair(weight, x)); } // Selecting 1 as the starting node - minimumCost = prim(1); - std::cout << minimumCost << std::endl; + int minimum_cost = prim(1, graph); + std::cout << minimum_cost << std::endl; return 0; } From 95227af3bc02ada95a0e068061c2ccc15408faa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 23:41:48 -0700 Subject: [PATCH 20/31] Fix linter for connected_components_with_dsu --- graph/connected_components_with_dsu.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/graph/connected_components_with_dsu.cpp b/graph/connected_components_with_dsu.cpp index aa03bef8f..71731e9da 100644 --- a/graph/connected_components_with_dsu.cpp +++ b/graph/connected_components_with_dsu.cpp @@ -13,8 +13,9 @@ void make_set() { // function the initialize every node as it's own parent } // To find the component where following node belongs to int find_set(int v) { - if (v == parent[v]) + if (v == parent[v]) { return v; + } return parent[v] = find_set(parent[v]); } @@ -22,8 +23,9 @@ void union_sets(int a, int b) { // To join 2 components to belong to one a = find_set(a); b = find_set(b); if (a != b) { - if (siz[a] < siz[b]) + if (siz[a] < siz[b]) { std::swap(a, b); + } parent[b] = a; siz[a] += siz[b]; } @@ -42,10 +44,10 @@ int main() { parent.resize(N + 1); siz.resize(N + 1); make_set(); - int edges; + int edges = 0; std::cin >> edges; // no of edges in the graph while (edges--) { - int node_a, node_b; + int node_a = 0, node_b = 0; std::cin >> node_a >> node_b; union_sets(node_a, node_b); } From 146f1c08b5d7ca237e68a5e5b741315c0a21dcc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 23:55:04 -0700 Subject: [PATCH 21/31] Fix linter warnings in ford_fulkerson --- ...th_ford_fulkerson_and_edmond_karp_algo.cpp | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp b/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp index cbd6bc15c..87b2fa101 100644 --- a/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp +++ b/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp @@ -16,16 +16,14 @@ // std::max capacity of node in graph const int MAXN = 505; class Graph { - int residual_capacity[MAXN][MAXN]; - int capacity[MAXN][MAXN]; // used while checking the flow of edge - int total_nodes; - int total_edges, source, sink; - int parent[MAXN]; + std::vector< std::vector > residual_capacity, capacity; + int total_nodes = 0; + int total_edges = 0, source = 0, sink = 0; + std::vector parent; std::vector > edge_participated; std::bitset visited; int max_flow = 0; bool bfs(int source, int sink) { // to find the augmented - path - memset(parent, -1, sizeof(parent)); visited.reset(); std::queue q; q.push(source); @@ -49,16 +47,17 @@ class Graph { } public: - Graph() { memset(residual_capacity, 0, sizeof(residual_capacity)); } - void set_graph(void) { + void set_graph() { std::cin >> total_nodes >> total_edges >> source >> sink; - for (int start, destination, capacity_, i = 0; i < total_edges; ++i) { + parent = std::vector(total_nodes, -1); + capacity = residual_capacity = std::vector< std::vector >(total_nodes, std::vector(total_nodes)); + for (int start = 0, destination = 0, capacity_ = 0, i = 0; i < total_edges; ++i) { std::cin >> start >> destination >> capacity_; residual_capacity[start][destination] = capacity_; capacity[start][destination] = capacity_; } } - void ford_fulkerson(void) { + void ford_fulkerson() { while (bfs(source, sink)) { int current_node = sink; int flow = std::numeric_limits::max(); @@ -77,12 +76,12 @@ class Graph { } } } - void print_flow_info(void) { + void print_flow_info() { for (int i = 0; i < total_nodes; ++i) { for (int j = 0; j < total_nodes; ++j) { if (capacity[i][j] && residual_capacity[i][j] < capacity[i][j]) { - edge_participated.push_back(std::make_tuple( + edge_participated.emplace_back(std::make_tuple( i, j, capacity[i][j] - residual_capacity[i][j])); } } @@ -92,14 +91,14 @@ class Graph { << '\n'; std::cout << "\nSource\tDestination\tCapacity\total_nodes"; for (auto& edge_data : edge_participated) { - int source, destination, capacity_; + int source = 0, destination = 0, capacity_ = 0; std::tie(source, destination, capacity_) = edge_data; std::cout << source << "\t" << destination << "\t\t" << capacity_ << '\t'; } } }; -int main(void) { +int main() { /* Input Graph: (for testing ) 4 5 0 3 From 1f9da87c129e3763f94af46f8038b7123ee88840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 3 Aug 2020 23:57:57 -0700 Subject: [PATCH 22/31] Fix global variable name for connected_component_with_dsu. --- graph/connected_components_with_dsu.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/graph/connected_components_with_dsu.cpp b/graph/connected_components_with_dsu.cpp index 71731e9da..50d0c4242 100644 --- a/graph/connected_components_with_dsu.cpp +++ b/graph/connected_components_with_dsu.cpp @@ -2,13 +2,13 @@ #include #include -int N; // denotes number of nodes; +int number_of_nodes; // denotes number of nodes; std::vector parent; -std::vector siz; +std::vector connected_set_size; void make_set() { // function the initialize every node as it's own parent - for (int i = 1; i <= N; i++) { + for (int i = 1; i <= number_of_nodes; i++) { parent[i] = i; - siz[i] = 1; + connected_set_size[i] = 1; } } // To find the component where following node belongs to @@ -23,26 +23,26 @@ void union_sets(int a, int b) { // To join 2 components to belong to one a = find_set(a); b = find_set(b); if (a != b) { - if (siz[a] < siz[b]) { + if (connected_set_size[a] < connected_set_size[b]) { std::swap(a, b); } parent[b] = a; - siz[a] += siz[b]; + connected_set_size[a] += connected_set_size[b]; } } int no_of_connected_components() { // To find total no of connected components std::set temp; // temp set to count number of connected components - for (int i = 1; i <= N; i++) temp.insert(find_set(i)); + for (int i = 1; i <= number_of_nodes; i++) temp.insert(find_set(i)); return temp.size(); } // All critical/corner cases have been taken care of. // Input your required values: (not hardcoded) int main() { - std::cin >> N; - parent.resize(N + 1); - siz.resize(N + 1); + std::cin >> number_of_nodes; + parent.resize(number_of_nodes + 1); + connected_set_size.resize(number_of_nodes + 1); make_set(); int edges = 0; std::cin >> edges; // no of edges in the graph From 5dbf857fb41bfbbd70b012a4c6014bcfb7e451ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Tue, 4 Aug 2020 00:00:52 -0700 Subject: [PATCH 23/31] Fix global variable name in topological_sort. --- graph/topological_sort.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/graph/topological_sort.cpp b/graph/topological_sort.cpp index f77780cdc..3827b9bcf 100644 --- a/graph/topological_sort.cpp +++ b/graph/topological_sort.cpp @@ -2,44 +2,44 @@ #include #include -int n, m; // For number of Vertices (V) and number of edges (E) -std::vector> G; +int number_of_vertices, number_of_edges; // For number of Vertices (V) and number of edges (E) +std::vector> graph; std::vector visited; -std::vector ans; +std::vector topological_order; void dfs(int v) { visited[v] = true; - for (int u : G[v]) { + for (int u : graph[v]) { if (!visited[u]) { dfs(u); } } - ans.push_back(v); + topological_order.push_back(v); } void topological_sort() { - visited.assign(n, false); - ans.clear(); - for (int i = 0; i < n; ++i) { + visited.assign(number_of_vertices, false); + topological_order.clear(); + for (int i = 0; i < number_of_vertices; ++i) { if (!visited[i]) { dfs(i); } } - reverse(ans.begin(), ans.end()); + reverse(topological_order.begin(), topological_order.end()); } int main() { std::cout << "Enter the number of vertices and the number of directed edges\n"; - std::cin >> n >> m; + std::cin >> number_of_vertices >> number_of_edges; int x = 0, y = 0; - G.resize(n, std::vector()); - for (int i = 0; i < n; ++i) { + graph.resize(number_of_vertices, std::vector()); + for (int i = 0; i < number_of_edges; ++i) { std::cin >> x >> y; x--, y--; // to convert 1-indexed to 0-indexed - G[x].push_back(y); + graph[x].push_back(y); } topological_sort(); std::cout << "Topological Order : \n"; - for (int v : ans) { + for (int v : topological_order) { std::cout << v + 1 << ' '; // converting zero based indexing back to one based. } From a2178f33cd7632cfda9a7f46d4ef6a76e26d0e39 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 8 Aug 2020 00:39:39 +0000 Subject: [PATCH 24/31] updating DIRECTORY.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 21953a553..b6070388a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -84,7 +84,7 @@ * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) * [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kruskal.cpp) - * [Lca](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lca.cpp) + * [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lowest_common_ancestor.cpp) * [Max Flow With Ford Fulkerson And Edmond Karp Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp) * [Prim](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/prim.cpp) * [Topological Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/topological_sort.cpp) From b7383ed5523599d5c9a4f1b2c38dbbf31f21f56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Sat, 8 Aug 2020 13:02:14 -0700 Subject: [PATCH 25/31] Undo changs in cycle check. --- graph/cycle_check_directed_graph.cpp | 357 +++++++++++++++++++++++---- 1 file changed, 304 insertions(+), 53 deletions(-) diff --git a/graph/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp index cb36a13c8..8a651cfc5 100644 --- a/graph/cycle_check_directed_graph.cpp +++ b/graph/cycle_check_directed_graph.cpp @@ -1,62 +1,313 @@ -#include -#include -#include -using std::vector; -using std::pair; +/** + * @file cycle_check_directed graph.cpp + * + * @brief BFS and DFS algorithms to check for cycle in a directed graph. + * + * @author [Anmol3299](mailto:mittalanmol22@gmail.com) + * + */ -void explore(int i, const vector> &adj, std::vector *state) -{ - (*state)[i] = 1; - for (const auto it2 : adj[i]) - { - if ((*state)[it2] == 0) - { - explore(it2, adj, state); - } - if ((*state)[it2] == 1) - { - std::cout<<"1"; - exit(0); - } - } - (*state)[i] = 2; +#include // for std::cout +#include // for std::map +#include // for std::queue +#include // for throwing errors +#include // for std::remove_reference +#include // for std::move +#include // for std::vector + +/** + * Implementation of non-weighted directed edge of a graph. + * + * The source vertex of the edge is labelled "src" and destination vertex is + * labelled "dest". + */ +struct Edge { + unsigned int src; + unsigned int dest; + + Edge() = delete; + ~Edge() = default; + Edge(Edge&&) = default; + Edge& operator=(Edge&&) = default; + Edge(Edge const&) = default; + Edge& operator=(Edge const&) = default; + + /** Set the source and destination of the vertex. + * + * @param source is the source vertex of the edge. + * @param destination is the destination vertex of the edge. + */ + Edge(unsigned int source, unsigned int destination) + : src(source), dest(destination) {} }; -int acyclic(const vector > &adj, size_t n) { - //write your code here - // permitted states are 0 1 and 2 - std::vector state(n, 0); +using AdjList = std::map>; - // mark the states of all vertices initially to 0 - for (size_t i = 0; i < n; i++) - { - state[i] = 0; - } +/** + * Implementation of graph class. + * + * The graph will be represented using Adjacency List representation. + * This class contains 2 data members "m_vertices" & "m_adjList" used to + * represent the number of vertices and adjacency list of the graph + * respectively. The vertices are labelled 0 - (m_vertices - 1). + */ +class Graph { + public: + Graph() : m_adjList({}) {} + ~Graph() = default; + Graph(Graph&&) = default; + Graph& operator=(Graph&&) = default; + Graph(Graph const&) = default; + Graph& operator=(Graph const&) = default; - for (size_t it1 = 0; it1 != adj.size(); it1++) - { - if (state[it1] == 0) - { - explore(it1, adj, &state); + /** Create a graph from vertices and adjacency list. + * + * @param vertices specify the number of vertices the graph would contain. + * @param adjList is the adjacency list representation of graph. + */ + Graph(unsigned int vertices, AdjList adjList) + : m_vertices(vertices), m_adjList(std::move(adjList)) {} + + /** Create a graph from vertices and adjacency list. + * + * @param vertices specify the number of vertices the graph would contain. + * @param adjList is the adjacency list representation of graph. + */ + Graph(unsigned int vertices, AdjList&& adjList) + : m_vertices(vertices), m_adjList(std::move(adjList)) {} + + /** Create a graph from vertices and a set of edges. + * + * Adjacency list of the graph would be created from the set of edges. If + * the source or destination of any edge has a value greater or equal to + * number of vertices, then it would throw a range_error. + * + * @param vertices specify the number of vertices the graph would contain. + * @param edges is a vector of edges. + */ + Graph(unsigned int vertices, std::vector const& edges) + : m_vertices(vertices) { + for (auto const& edge : edges) { + if (edge.src >= vertices || edge.dest >= vertices) { + throw std::range_error( + "Either src or dest of edge out of range"); + } + m_adjList[edge.src].emplace_back(edge.dest); + } } - if (state[it1] == 1) - { - std::cout<<"1"; - exit(0); - } - } - std::cout<<"0"; - return 0; -} + /** Return a const reference of the adjacency list. + * + * @return const reference to the adjacency list + */ + std::remove_reference::type const& getAdjList() const { + return m_adjList; + } + + /** + * @return number of vertices in the graph. + */ + unsigned int getVertices() const { return m_vertices; } + + /** Add vertices in the graph. + * + * @param num is the number of vertices to be added. It adds 1 vertex by + * default. + * + */ + void addVertices(unsigned int num = 1) { m_vertices += num; } + + /** Add an edge in the graph. + * + * @param edge that needs to be added. + */ + void addEdge(Edge const& edge) { + if (edge.src >= m_vertices || edge.dest >= m_vertices) { + throw std::range_error("Either src or dest of edge out of range"); + } + m_adjList[edge.src].emplace_back(edge.dest); + } + + /** Add an Edge in the graph + * + * @param source is source vertex of the edge. + * @param destination is the destination vertex of the edge. + */ + void addEdge(unsigned int source, unsigned int destination) { + if (source >= m_vertices || destination >= m_vertices) { + throw std::range_error( + "Either source or destination of edge out of range"); + } + m_adjList[source].emplace_back(destination); + } + + private: + unsigned int m_vertices = 0; + AdjList m_adjList; +}; + +/** + * Check if a directed graph has a cycle or not. + * + * This class provides 2 methods to check for cycle in a directed graph: + * isCyclicDFS & isCyclicBFS. + * + * - isCyclicDFS uses DFS traversal method to check for cycle in a graph. + * - isCyclidBFS used BFS traversal method to check for cycle in a graph. + */ +class CycleCheck { + private: + enum nodeStates : uint8_t { not_visited = 0, in_stack, visited }; + + /** Helper function of "isCyclicDFS". + * + * @param adjList is the adjacency list representation of some graph. + * @param state is the state of the nodes of the graph. + * @param node is the node being evaluated. + * + * @return true if graph has a cycle, else false. + */ + static bool isCyclicDFSHelper(AdjList const& adjList, + std::vector* state, + unsigned int node) { + // Add node "in_stack" state. + (*state)[node] = in_stack; + + // If the node has children, then recursively visit all children of the + // node. + auto const it = adjList.find(node); + if (it != adjList.end()) { + for (auto child : it->second) { + // If state of child node is "not_visited", evaluate that child + // for presence of cycle. + auto state_of_child = (*state)[child]; + if (state_of_child == not_visited) { + if (isCyclicDFSHelper(adjList, state, child)) { + return true; + } + } else if (state_of_child == in_stack) { + // If child node was "in_stack", then that means that there + // is a cycle in the graph. Return true for presence of the + // cycle. + return true; + } + } + } + + // Current node has been evaluated for the presence of cycle and had no + // cycle. Mark current node as "visited". + (*state)[node] = visited; + // Return that current node didn't result in any cycles. + return false; + } + + public: + /** Driver function to check if a graph has a cycle. + * + * This function uses DFS to check for cycle in the graph. + * + * @param graph which needs to be evaluated for the presence of cycle. + * @return true if a cycle is detected, else false. + */ + static bool isCyclicDFS(Graph const& graph) { + auto vertices = graph.getVertices(); + + /** State of the node. + * + * It is a vector of "nodeStates" which represents the state node is in. + * It can take only 3 values: "not_visited", "in_stack", and "visited". + * + * Initially, all nodes are in "not_visited" state. + */ + std::vector state(vertices, not_visited); + + // Start visiting each node. + for (unsigned int node = 0; node < vertices; node++) { + // If a node is not visited, only then check for presence of cycle. + // There is no need to check for presence of cycle for a visited + // node as it has already been checked for presence of cycle. + if (state[node] == not_visited) { + // Check for cycle. + if (isCyclicDFSHelper(graph.getAdjList(), &state, node)) { + return true; + } + } + } + + // All nodes have been safely traversed, that means there is no cycle in + // the graph. Return false. + return false; + } + + /** Check if a graph has cycle or not. + * + * This function uses BFS to check if a graph is cyclic or not. + * + * @param graph which needs to be evaluated for the presence of cycle. + * @return true if a cycle is detected, else false. + */ + static bool isCyclicBFS(Graph const& graph) { + auto graphAjdList = graph.getAdjList(); + auto vertices = graph.getVertices(); + + std::vector indegree(vertices, 0); + // Calculate the indegree i.e. the number of incident edges to the node. + for (auto const& list : graphAjdList) { + auto children = list.second; + for (auto const& child : children) { + indegree[child]++; + } + } + + std::queue can_be_solved; + for (unsigned int node = 0; node < vertices; node++) { + // If a node doesn't have any input edges, then that node will + // definately not result in a cycle and can be visited safely. + if (!indegree[node]) { + can_be_solved.emplace(node); + } + } + + // Vertices that need to be traversed. + auto remain = vertices; + // While there are safe nodes that we can visit. + while (!can_be_solved.empty()) { + auto solved = can_be_solved.front(); + // Visit the node. + can_be_solved.pop(); + // Decrease number of nodes that need to be traversed. + remain--; + + // Visit all the children of the visited node. + auto it = graphAjdList.find(solved); + if (it != graphAjdList.end()) { + for (auto child : it->second) { + // Check if we can visited the node safely. + if (--indegree[child] == 0) { + // if node can be visited safely, then add that node to + // the visit queue. + can_be_solved.emplace(child); + } + } + } + } + + // If there are still nodes that we can't visit, then it means that + // there is a cycle and return true, else return false. + return !(remain == 0); + } +}; + +/** + * Main function. + */ int main() { - size_t n = 0, m = 0; - std::cin >> n >> m; - vector > adj(n, vector()); - for (size_t i = 0; i < m; i++) { - int x = 0, y = 0; - std::cin >> x >> y; - adj[x - 1].push_back(y - 1); - } - acyclic(adj,n); + // Instantiate the graph. + Graph g(7, std::vector{{0, 1}, {1, 2}, {2, 0}, {2, 5}, {3, 5}}); + // Check for cycle using BFS method. + std::cout << CycleCheck::isCyclicBFS(g) << '\n'; + + // Check for cycle using DFS method. + std::cout << CycleCheck::isCyclicDFS(g) << '\n'; + return 0; } From 2e43bbdfb30d1ed115f0fe1597bd22e59d57d2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Sat, 8 Aug 2020 19:12:03 -0700 Subject: [PATCH 26/31] Rename dfs to depth_first_search.: --- DIRECTORY.md | 4 ++-- graph/{dfs.cpp => depth_first_search.cpp} | 0 .../{dfs_with_stack.cpp => depth_first_search_with_stack.cpp} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename graph/{dfs.cpp => depth_first_search.cpp} (100%) rename graph/{dfs_with_stack.cpp => depth_first_search_with_stack.cpp} (100%) diff --git a/DIRECTORY.md b/DIRECTORY.md index 76fa1154d..3ad77d592 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -78,8 +78,8 @@ * [Connected Components](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components.cpp) * [Connected Components With Dsu](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components_with_dsu.cpp) * [Cycle Check Directed Graph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/cycle_check_directed_graph.cpp) - * [Dfs](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dfs.cpp) - * [Dfs With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dfs_with_stack.cpp) + * [Depth-First Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search.cpp) + * [Depth-First Search With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search_with_stack.cpp) * [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dijkstra.cpp) * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) diff --git a/graph/dfs.cpp b/graph/depth_first_search.cpp similarity index 100% rename from graph/dfs.cpp rename to graph/depth_first_search.cpp diff --git a/graph/dfs_with_stack.cpp b/graph/depth_first_search_with_stack.cpp similarity index 100% rename from graph/dfs_with_stack.cpp rename to graph/depth_first_search_with_stack.cpp From f7ff88e7d73e379c62c328b9cc2b3e1093fce8de Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 9 Aug 2020 02:14:27 +0000 Subject: [PATCH 27/31] updating DIRECTORY.md --- DIRECTORY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 3ad77d592..119200746 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -78,8 +78,8 @@ * [Connected Components](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components.cpp) * [Connected Components With Dsu](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components_with_dsu.cpp) * [Cycle Check Directed Graph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/cycle_check_directed_graph.cpp) - * [Depth-First Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search.cpp) - * [Depth-First Search With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search_with_stack.cpp) + * [Depth First Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search.cpp) + * [Depth First Search With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search_with_stack.cpp) * [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dijkstra.cpp) * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) From 78ecea32743f539d8a14d0f6e1678e41368960d5 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 16 Aug 2020 19:32:56 +0000 Subject: [PATCH 28/31] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 76fa1154d..60f4717a4 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -82,6 +82,7 @@ * [Dfs With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dfs_with_stack.cpp) * [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dijkstra.cpp) * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) + * [Is Graph Bipartite](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/is_graph_bipartite.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) * [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kruskal.cpp) * [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lowest_common_ancestor.cpp) From d50f1c67c851a6f0c8d547551efef52ba618e092 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 16 Aug 2020 19:33:27 +0000 Subject: [PATCH 29/31] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 119200746..dff4ab078 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -82,6 +82,7 @@ * [Depth First Search With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/depth_first_search_with_stack.cpp) * [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dijkstra.cpp) * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) + * [Is Graph Bipartite](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/is_graph_bipartite.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) * [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kruskal.cpp) * [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lowest_common_ancestor.cpp) From 9927b462059075c74a5a85952de42cade8c73f08 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:36:56 +0000 Subject: [PATCH 30/31] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index dff4ab078..0479e61dd 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -70,6 +70,7 @@ * [Tree Height](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/tree_height.cpp) ## Geometry + * [Jarvis Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/jarvis_algorithm.cpp) * [Line Segment Intersection](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/line_segment_intersection.cpp) ## Graph From c1a2e33f2f0396fc21c93f799cfbd47101bd3dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Hl=C3=A1sek?= Date: Mon, 17 Aug 2020 20:10:03 -0700 Subject: [PATCH 31/31] Adjust comment. --- graph/depth_first_search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/depth_first_search.cpp b/graph/depth_first_search.cpp index e3f4e7ece..e99d44fc9 100644 --- a/graph/depth_first_search.cpp +++ b/graph/depth_first_search.cpp @@ -54,7 +54,7 @@ namespace graph { * */ void addEdge(std::vector> *adj, size_t u, size_t v) { - /** + /* * * Here we are considering undirected graph that's the * reason we are adding v to the adjacency list representation of u