diff --git a/CMakeLists.txt b/CMakeLists.txt index bfaeccdbe..8986df14c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,8 @@ add_subdirectory(probability) add_subdirectory(data_structures) add_subdirectory(machine_learning) add_subdirectory(numerical_methods) - +add_subdirectory(graph) + cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0057 NEW) find_package(Doxygen OPTIONAL_COMPONENTS dot dia) diff --git a/graph/CMakeLists.txt b/graph/CMakeLists.txt new file mode 100644 index 000000000..02b8f4840 --- /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 + ) + if(OpenMP_CXX_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_CXX) + endif() + install(TARGETS ${testname} DESTINATION "bin/graph") + +endforeach( testsourcefile ${APP_SOURCES} ) 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/connected_components.cpp b/graph/connected_components.cpp index e53dbf424..06bb1ee50 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
@@ -26,97 +26,123 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 
-using std::vector;
-
 /**
- * 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;
-
-    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;
-    }
-};
 
+namespace graph {
 /**
- * \brief Function that add edge between two nodes or vertices of 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 graph::addEdge(int u, int v) {
-    adj[u - 1].push_back(v - 1);
-    adj[v - 1].push_back(u - 1);
+void addEdge(std::vector> *adj, 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
+ * @brief Utility function for depth first seach algorithm
+ * this function explores the vertex which is passed into.
+ *
+ * @param adj adjacency list of graph.
+ * @param u vertex or node to be explored.
+ * @param visited already visited vertices.
  */
-void graph::depth_first_search() {
-    int n = adj.size();
-    vector visited(n, false);
+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 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();
+    int connected_components = 0;
+    std::vector visited(n, false);
 
     for (int i = 0; i < n; i++) {
         if (!visited[i]) {
-            explore(i, visited);
+            explore(adj, i, &visited);
             connected_components++;
         }
     }
+    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 vertex
- */
-void graph::explore(int u, vector &visited) {
-    visited[u] = true;
-    for (auto v : adj[u]) {
-        if (!visited[v]) {
-            explore(v, visited);
-        }
-    }
+}  // 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();
 
-    /// Adding edges between vertices
-    g.addEdge(1, 2);
-    g.addEdge(3, 2);
+    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;
 
-    /// printing the connected components
-    std::cout << g.getConnectedComponents();
+    std::vector> adj(vertices, std::vector());
+
+    int u = int(), v = int();
+    while (edges--) {
+        std::cin >> u >> v;
+        graph::addEdge(&adj, u, v);
+    }
+
+    int cc = graph::getConnectedComponents(&adj);
+    std::cout << cc << std::endl;
     return 0;
 }
diff --git a/graph/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp
index a9e4f2c8b..c991730c0 100644
--- a/graph/cycle_check_directed_graph.cpp
+++ b/graph/cycle_check_directed_graph.cpp
@@ -1,313 +1,57 @@
-/**
- * @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)
- *
- */
+#include 
+#include 
+#include 
+using std::vector;
+using std::pair;
 
-#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) {}
+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::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::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;
-    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() {
-    // 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 650f0cd51..ac269de18 100644 --- a/graph/dijkstra.cpp +++ b/graph/dijkstra.cpp @@ -1,52 +1,180 @@ -#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 #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); +#include - for (int i = 1; i <= n; i++) - if (dis[i] == INF) - cout << "-1 "; - else - cout << dis[i] << " "; - return 0; +constexpr int64_t INF = std::numeric_limits::max(); + +/** + * @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 = 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>()); + + 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; } 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; }