diff --git a/CMakeLists.txt b/CMakeLists.txt index 57104aa9c..f75d558f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,8 @@ add_subdirectory(backtracking) 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/CONTRIBUTING.md b/CONTRIBUTING.md index 35d875d43..07d620dea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,8 @@ We are very happy that you consider implementing algorithms and data structures - Please use the directory structure of the repository. - File extension for code should be *.h *.cpp. - Don't use **bits/stdc++.h** because this is quite Linux specific and slows down the compilation process. -- Avoid using **struct** and instead use the **class** keyword. +- Organize your code using **`struct`**, **`class`** and/or **`namespace`** keywords +- If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines). - You can suggest reasonable changes to existing algorithms. - Strictly use snake_case (underscore_separated) in filenames. - If you have added or modified code, please make sure the code compiles before submitting. @@ -116,6 +117,7 @@ my_new_cpp_class.cpp is correct format ``` - It will be used to dynamically create a directory of files and implementation. - File name validation will run on docker to ensure the validity. +- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example, if `median_search.cpp` already exists in the `search` folder and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`. #### New Directory guidelines - We recommend adding files to existing directories as much as possible. diff --git a/DIRECTORY.md b/DIRECTORY.md index 60f4717a4..178e88499 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -67,9 +67,11 @@ * [Longest Increasing Subsequence (Nlogn)](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/longest_increasing_subsequence_(nlogn).cpp) * [Matrix Chain Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/matrix_chain_multiplication.cpp) * [Searching Of Element In Dynamic Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/searching_of_element_in_dynamic_array.cpp) + * [Shortest Common Supersequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/shortest_common_supersequence.cpp) * [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 @@ -78,8 +80,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) * [Is Graph Bipartite](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/is_graph_bipartite.cpp) @@ -111,7 +113,9 @@ * [Adaline Learning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/adaline_learning.cpp) * [Kohonen Som Topology](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_topology.cpp) * [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_trace.cpp) + * [Neural Network](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/neural_network.cpp) * [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/ordinary_least_squares_regressor.cpp) + * [Vector Ops](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/vector_ops.hpp) ## Math * [Armstrong Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/armstrong_number.cpp) @@ -180,7 +184,7 @@ * [Decimal To Binary](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_binary.cpp) * [Decimal To Hexadecimal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_hexadecimal.cpp) * [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp) - * [Fast Interger Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_interger_input.cpp) + * [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_integer_input.cpp) * [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/happy_number.cpp) * [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/matrix_exponentiation.cpp) * [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/palindrome_of_number.cpp) @@ -202,6 +206,7 @@ ## Range Queries * [Fenwick Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/fenwick_tree.cpp) + * [Heavy Light Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/heavy_light_decomposition.cpp) * [Mo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/mo.cpp) * [Segtree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/segtree.cpp) @@ -236,6 +241,7 @@ * [Non Recursive Merge Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/non_recursive_merge_sort.cpp) * [Numeric String Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/numeric_string_sort.cpp) * [Odd Even Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/odd_even_sort.cpp) + * [Pigeonhole Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/pigeonhole_sort.cpp) * [Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort.cpp) * [Quick Sort 3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort_3.cpp) * [Radix Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort.cpp) diff --git a/dynamic_programming/shortest_common_supersequence.cpp b/dynamic_programming/shortest_common_supersequence.cpp new file mode 100644 index 000000000..3064359fb --- /dev/null +++ b/dynamic_programming/shortest_common_supersequence.cpp @@ -0,0 +1,179 @@ +/** + * @file + * @brief SCS is a string Z which is the shortest supersequence of strings X and Y (may not be continuous in Z, but order is maintained). + * + * @details + * The idea is to use lookup table method as used in LCS. + * For example: example 1:- + * X: 'ABCXYZ', Y: 'ABZ' then Z will be 'ABCXYZ' (y is not continuous but in order) + * + * For example: example 2:- + * X: 'AGGTAB', Y: 'GXTXAYB' then Z will be 'AGGXTXAYB' + * @author [Ridhish Jain](https://github.com/ridhishjain) + * @see more on [SCS](https://en.wikipedia.org/wiki/Shortest_common_supersequence_problem) + * @see related problem [Leetcode](https://leetcode.com/problems/shortest-common-supersequence/) +*/ + +// header files +#include +#include +#include +#include +#include + +/** + * @namespace dynamic_programming + * @brief Dynamic Programming algorithms +*/ +namespace dynamic_programming { + + /** + * @namespace shortest_common_supersequence + * @brief Shortest Common Super Sequence algorithm + */ + namespace shortest_common_supersequence { + + /** + * Function implementing Shortest Common Super-Sequence algorithm using look-up table method. + * @param str1 first string 'X' + * @param str2 second string 'Y' + * @returns string 'Z', superSequence of X and Y + */ + std::string scs(const std::string &str1, const std::string &str2) { + + // Edge cases + // If either str1 or str2 or both are empty + if(str1.empty() && str2.empty()) { + return ""; + } + else if(str1.empty()) { + return str2; + } + else if(str2.empty()) { + return str1; + } + + // creating lookup table + std::vector > lookup(str1.length() + 1, std::vector (str2.length() + 1, 0)); + + for(int i=1; i <= str1.length(); i++) { + for(int j=1; j <= str2.length(); j++) { + if(str1[i-1] == str2[j-1]) { + lookup[i][j] = lookup[i-1][j-1] + 1; + } + else { + lookup[i][j] = std::max(lookup[i-1][j], lookup[i][j-1]); + } + } + } + + // making supersequence + // i and j are initially pointed towards end of strings + // Super-sequence will be constructed backwards + int i=str1.length(); + int j=str2.length(); + std::string s; + + while(i>0 && j>0) { + + // If the characters at i and j of both strings are same + // We only need to add them once in s + if(str1[i-1] == str2[j-1]) { + s.push_back(str1[i-1]); + i--; + j--; + } + // otherwise we check lookup table for recurrences of characters + else { + if(lookup[i-1][j] > lookup[i][j-1]) { + s.push_back(str1[i-1]); + i--; + } + else { + s.push_back(str2[j-1]); + j--; + } + } + } + + // copying remaining elements + // if j becomes 0 before i + while(i > 0) { + s.push_back(str1[i-1]); + i--; + } + + // if i becomes 0 before j + while(j > 0) { + s.push_back(str2[j-1]); + j--; + } + + // As the super sequence is constructd backwards + // reversing the string before returning gives us the correct output + reverse(s.begin(), s.end()); + return s; + } + } // namespace shortest_common_supersequence +} // namespace dynamic_programming + +/** + * Test Function + * @return void +*/ +static void test() { + // custom input vector + std::vector > scsStrings { + {"ABCXYZ", "ABZ"}, + {"ABZ", "ABCXYZ"}, + {"AGGTAB", "GXTXAYB"}, + {"X", "Y"}, + }; + + // calculated output vector by scs function + std::vector calculatedOutput(4, ""); + int i=0; + for(auto & scsString : scsStrings) { + + calculatedOutput[i] = dynamic_programming::shortest_common_supersequence::scs( + scsString[0], scsString[1] + ); + i++; + } + + // expected output vector acc to problem statement + std::vector expectedOutput { + "ABCXYZ", + "ABCXYZ", + "AGGXTXAYB", + "XY" + }; + + // Testing implementation via assert function + // It will throw error if any of the expected test fails + // Else it will give nothing + for(int i=0; i < scsStrings.size(); i++) { + assert(expectedOutput[i] == calculatedOutput[i]); + } + + std::cout << "All tests passed successfully!\n"; + return; +} + +/** Main function (driver code)*/ +int main() { + // test for implementation + test(); + + // user input + std::string s1, s2; + std::cin >> s1; + std::cin >> s2; + + std::string ans; + + // user output + ans = dynamic_programming::shortest_common_supersequence::scs(s1, s2); + std::cout << ans; + return 0; +} diff --git a/geometry/jarvis_algorithm.cpp b/geometry/jarvis_algorithm.cpp new file mode 100644 index 000000000..ae5b1b5a6 --- /dev/null +++ b/geometry/jarvis_algorithm.cpp @@ -0,0 +1,179 @@ +/** + * @file + * @brief Implementation of [Jarvis’s](https://en.wikipedia.org/wiki/Gift_wrapping_algorithm) algorithm. + * + * @details + * Given a set of points in the plane. the convex hull of the set + * is the smallest convex polygon that contains all the points of it. + * + * ### Algorithm + * The idea of Jarvis’s Algorithm is simple, we start from the leftmost point + * (or point with minimum x coordinate value) and we + * keep wrapping points in counterclockwise direction. + * + * The idea is to use orientation() here. Next point is selected as the + * point that beats all other points at counterclockwise orientation, i.e., + * next point is q if for any other point r, + * we have “orientation(p, q, r) = counterclockwise”. + * + * For Example, + * If points = {{0, 3}, {2, 2}, {1, 1}, {2, 1}, + {3, 0}, {0, 0}, {3, 3}}; + * + * then the convex hull is + * (0, 3), (0, 0), (3, 0), (3, 3) + * + * @author [Rishabh Agarwal](https://github.com/rishabh-997) + */ + +#include +#include +#include + +/** + * @namespace geometry + * @brief Geometry algorithms + */ +namespace geometry { + /** + * @namespace jarvis + * @brief Functions for [Jarvis’s](https://en.wikipedia.org/wiki/Gift_wrapping_algorithm) algorithm + */ + namespace jarvis { + /** + * Structure defining the x and y co-ordinates of the given + * point in space + */ + struct Point { + int x, y; + }; + + /** + * Class which can be called from main and is globally available + * throughout the code + */ + class Convexhull { + std::vector points; + int size; + + public: + /** + * Constructor of given class + * + * @param pointList list of all points in the space + * @param n number of points in space + */ + explicit Convexhull(const std::vector &pointList) { + points = pointList; + size = points.size(); + } + + /** + * Creates convex hull of a set of n points. + * There must be 3 points at least for the convex hull to exist + * + * @returns an vector array containing points in space + * which enclose all given points thus forming a hull + */ + std::vector getConvexHull() const { + // Initialize Result + std::vector hull; + + // Find the leftmost point + int leftmost_point = 0; + for (int i = 1; i < size; i++) { + if (points[i].x < points[leftmost_point].x) { + leftmost_point = i; + } + } + // Start from leftmost point, keep moving counterclockwise + // until reach the start point again. This loop runs O(h) + // times where h is number of points in result or output. + int p = leftmost_point, q = 0; + do { + // Add current point to result + hull.push_back(points[p]); + + // Search for a point 'q' such that orientation(p, x, q) + // is counterclockwise for all points 'x'. The idea + // is to keep track of last visited most counter clock- + // wise point in q. If any point 'i' is more counter clock- + // wise than q, then update q. + q = (p + 1) % size; + for (int i = 0; i < size; i++) { + // If i is more counterclockwise than current q, then + // update q + if (orientation(points[p], points[i], points[q]) == 2) { + q = i; + } + } + + // Now q is the most counterclockwise with respect to p + // Set p as q for next iteration, so that q is added to + // result 'hull' + p = q; + + } while (p != leftmost_point); // While we don't come to first point + + return hull; + } + + /** + * This function returns the geometric orientation for the three points + * in a space, ie, whether they are linear ir clockwise or + * anti-clockwise + * @param p first point selected + * @param q adjacent point for q + * @param r adjacent point for q + * + * @returns 0 -> Linear + * @returns 1 -> Clock Wise + * @returns 2 -> Anti Clock Wise + */ + static int orientation(const Point &p, const Point &q, const Point &r) { + int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + + if (val == 0) { + return 0; + } + return (val > 0) ? 1 : 2; + } + + }; + + } // namespace jarvis +} // namespace geometry + +/** + * Test function + * @returns void + */ +static void test() { + std::vector points = {{0, 3}, + {2, 2}, + {1, 1}, + {2, 1}, + {3, 0}, + {0, 0}, + {3, 3} + }; + geometry::jarvis::Convexhull hull(points); + std::vector actualPoint; + actualPoint = hull.getConvexHull(); + + std::vector expectedPoint = {{0, 3}, + {0, 0}, + {3, 0}, + {3, 3}}; + for (int i = 0; i < expectedPoint.size(); i++) { + assert(actualPoint[i].x == expectedPoint[i].x); + assert(actualPoint[i].y == expectedPoint[i].y); + } + std::cout << "Test implementations passed!\n"; +} + +/** Driver Code */ +int main() { + test(); + return 0; +} 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/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp index a9e4f2c8b..8a651cfc5 100644 --- a/graph/cycle_check_directed_graph.cpp +++ b/graph/cycle_check_directed_graph.cpp @@ -53,7 +53,7 @@ using AdjList = std::map>; */ class Graph { public: - Graph() : m_vertices(0), m_adjList({}) {} + Graph() : m_adjList({}) {} ~Graph() = default; Graph(Graph&&) = default; Graph& operator=(Graph&&) = default; @@ -65,8 +65,8 @@ class Graph { * @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 const& adjList) - : m_vertices(vertices), m_adjList(adjList) {} + Graph(unsigned int vertices, AdjList adjList) + : m_vertices(vertices), m_adjList(std::move(adjList)) {} /** Create a graph from vertices and adjacency list. * @@ -142,7 +142,7 @@ class Graph { } private: - unsigned int m_vertices; + unsigned int m_vertices = 0; AdjList m_adjList; }; diff --git a/graph/depth_first_search.cpp b/graph/depth_first_search.cpp new file mode 100644 index 000000000..e99d44fc9 --- /dev/null +++ b/graph/depth_first_search.cpp @@ -0,0 +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 +#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); + } + } +} + +/** + * \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() { + size_t vertices = 0, edges = 0; + 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 = 0, v = 0; + 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; +} diff --git a/graph/depth_first_search_with_stack.cpp b/graph/depth_first_search_with_stack.cpp new file mode 100644 index 000000000..2d5752322 --- /dev/null +++ b/graph/depth_first_search_with_stack.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +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) { + std::cout << act << ' '; + for (auto it : graph[act]) { + stack.push(it); + if (checked[it] != BLACK) { + checked[it] = GREY; + } + } + checked[act] = BLACK; // nodo controllato + } + } +} + +int main() { + int n = 0; + std::cin >> n; + std::vector< std::list > graph(INF); + for (int i = 0; i < n; ++i) { + int u = 0, w = 0; + std::cin >> u >> w; + graph[u].push_back(w); + } + + dfs(graph, 0); + + return 0; +} diff --git a/graph/dfs.cpp b/graph/dfs.cpp deleted file mode 100644 index 2d38c8725..000000000 --- a/graph/dfs.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#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); - } - } -} - -void DFS_(int graph[4][4], int s) { - bool visited[v]; - memset(visited, 0, sizeof(visited)); - DFSUtil_(graph, visited, s); -} - -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; - return 0; -} \ No newline at end of file diff --git a/graph/dfs_with_stack.cpp b/graph/dfs_with_stack.cpp deleted file mode 100644 index 193f3f291..000000000 --- a/graph/dfs_with_stack.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include - -#define WHITE 0 -#define GREY 1 -#define BLACK 2 -#define INF 99999 - -using namespace std; - -int checked[999] = {WHITE}; - -void dfs(const list lista[], int start) { - stack stack; - - int checked[999] = {WHITE}; - - stack.push(start); - - checked[start] = GREY; - 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; - } - checked[act] = BLACK; // nodo controllato - } - } -} - -int main() { - int u, w; - int n; - cin >> n; - list lista[INF]; - for (int i = 0; i < n; ++i) { - cin >> u >> w; - lista[u].push_back(w); - } - - dfs(lista, 0); - - return 0; -} diff --git a/graph/kosaraju.cpp b/graph/kosaraju.cpp index 00c9d7ca0..5949c0bb8 100644 --- a/graph/kosaraju.cpp +++ b/graph/kosaraju.cpp @@ -4,77 +4,84 @@ #include #include +#include -using namespace std; /** * Iterative function/method to print graph: - * @param a[] : array of vectors (2D) - * @param V : vertices + * @param a adjacency list representation of the graph + * @param V number of vertices * @return void **/ -void print(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()) - cout << "i=" << i << "-->"; - for (int j = 0; j < a[i].size(); j++) cout << a[i][j] << " "; - if (!a[i].empty()) - cout << endl; + if (!a[i].empty()) { + std::cout << "i=" << i << "-->"; + } + for (int j : a[i]) { + std::cout << j << " "; + } + if (!a[i].empty()) { + std::cout << std::endl; + } } } /** * //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 adj[] : array of vectors to represent graph + * @param v vertices + * @param st stack passed by reference + * @param vis array to keep track of visited nodes (boolean type) + * @param adj adjacency list representation of the graph * @return void **/ -void push_vertex(int v, stack &st, bool vis[], 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 grev[] : graph with reversed edges + * @param v vertices + * @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[], 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, vector adj[]) { - bool vis[V] = {}; - stack st; +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[]: - 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, vector adj[]) { int t = st.top(); st.pop(); if (vis[t] == false) { - dfs(t, vis, grev); + dfs(t, &vis, grev); count_scc++; } } @@ -101,21 +108,21 @@ int kosaraju(int V, vector adj[]) { // All critical/corner cases have been taken care of. // Input your required values: (not hardcoded) int main() { - int t; - cin >> t; + int t = 0; + std::cin >> t; while (t--) { - int a, b; // a->number of nodes, b->directed edges. - cin >> a >> b; - int m, n; - vector adj[a + 1]; + int a = 0, b = 0; // a->number of nodes, b->directed edges. + std::cin >> a >> b; + 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. { - 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..e179131a1 100644 --- a/graph/kruskal.cpp +++ b/graph/kruskal.cpp @@ -1,73 +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; +using ll = int64_t; + +std::array parent; +ll node, edge; +std::vector>> edges; 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]]; @@ -75,41 +23,42 @@ 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 = 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); } } 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; + edges.emplace_back(make_pair(cost, std::make_pair(from, to))); totalcost += cost; } - sort(v.begin(), v.end()); - // rep(i,v.size()) - // cout<