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/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<