diff --git a/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mahmoud Aboelsoud).cpp b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mahmoud Aboelsoud).cpp new file mode 100644 index 000000000..2476c3a67 --- /dev/null +++ b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mahmoud Aboelsoud).cpp @@ -0,0 +1,100 @@ +// Author: Mahmoud Aboelsoud + +class Solution { +public: + // we need to find the number of edges that we can remove to make the graph fully traversable + // which mean we need the minimum number of edges to connect to make the graph fully traversable by Alice and Bob + // we can use DSU to solve this problem + // we can make two graphs one for Alice and one for Bob + // we need to find the minimum number of edges used in both graphs to make each graph connected + // then we can remove the edges that are not used in both graphs + // we can use the third type of edges to connect the nodes in both graphs + // then we can check the needed number of edges to make both graphs connected from the other two types of edges + + + // DSU implementation + struct DSU{ + + vector parent, set_size; + + DSU(int n){ + parent.assign(n + 1, 0); + set_size.assign(n + 1, 1); + + for(int i = 1; i <= n; i++) + parent[i] = i; + } + + int find_set(int v){ + if(v == parent[v]) return v; + + return parent[v] = find_set(parent[v]); + } + + void union_sets(int a, int b){ + a = find_set(a); + b = find_set(b); + if(a != b){ + if(set_size[a] < set_size[b]) + swap(a, b); + parent[b] = a; + set_size[a] += set_size[b]; + } + } + + bool same_set(int a, int b){ + a = find_set(a); + b = find_set(b); + + return a == b; + } + }; + + + int maxNumEdgesToRemove(int n, vector>& edges) { + // we make 2 DSU one for Alice and one for Bob + DSU dsu1(n), dsu2(n); + + // cnt: number of edges that is required to make each of the 2 graphs connected + int cnt = 0; + + // we can use the third type of edges to connect the nodes in both graphs + for(auto&i: edges){ + // if the edge is of type 3 and the nodes are not connected in both graphs + if(i[0] == 3 && !dsu1.same_set(i[1], i[2])){ + // we can use this edge to connect the nodes in both graphs + // we increase the number of required edges by 1 + cnt++; + // we connect the nodes in both graphs + dsu1.union_sets(i[1], i[2]); + dsu2.union_sets(i[1], i[2]); + } + } + + // we check the needed number of edges to make both graphs connected from the other two types of edges + for(auto&i: edges){ + // if the edge is of type 1 and the nodes are not connected in Alice's graph + if(i[0] == 1 && !dsu1.same_set(i[1], i[2])){ + // we can use this edge to connect the nodes in Alice's graph + dsu1.union_sets(i[1], i[2]); + // we increase the number of required edges by 1 + cnt++; + } + // if the edge is of type 2 and the nodes are not connected in Bob's graph + else if(i[0] == 2 && !dsu2.same_set(i[1], i[2])){ + // we can use this edge to connect the nodes in Bob's graph + dsu2.union_sets(i[1], i[2]); + // we increase the number of required edges by 1 + cnt++; + } + } + + // then we check if all nodes in the given graph are connected in both graphs + // we do that by checking if the number of nodes in the set of the first node is equal to the number of nodes in the graph + // if not then we return -1 + if(dsu1.set_size[dsu1.find_set(1)] != n || dsu2.set_size[dsu2.find_set(1)] != n) return -1; + + // else we return the number of edges that we can remove to make the graph fully traversable + return edges.size() - cnt; + } +}; diff --git a/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mina Magdy).cpp b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mina Magdy).cpp new file mode 100644 index 000000000..1070d195d --- /dev/null +++ b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Mina Magdy).cpp @@ -0,0 +1,54 @@ +// Author: Mina Magdy + +// create a structure for disjoint set union data structure +struct DSU { + int cc; // number of connected components + vector p, s; // vector for storing parent and size of connected components + DSU(int n) { // constructor + cc = n; // initially number of connected components are equal to the number of vertices + p.resize(n + 1); // resize vector to hold parent of each vertex + iota(p.begin(), p.end(), 0); // initialize the parent vector with indices + s.assign(n + 1, 1); // initially all connected components have size 1 + } + int find(int x) { // function to find the parent of a vertex and do path compression + return (x == p[x] ? x : p[x] = find(p[x])); + } + bool same_group(int u, int v) { // function to check if two vertices are in the same group or not + return find(u) == find(v); + } + void join(int u, int v) { // function to join two vertices into a single group + int r1 = find(u), r2 = find(v); + if (r1 == r2) // already in the same group + return; + if (s[r1] < s[r2]) // make smaller group as child of the larger group + swap(r1, r2); + p[r2] = r1; // make parent of r2 as r1 + s[r1] += s[r2]; // add size of r2 to size of r1 + cc--; // decrease the number of connected components + } +}; + +int maxNumEdgesToRemove(int n, vector>& edges) { + sort(edges.begin(), edges.end(), greater<>()); // sort the edges in descending order of type + DSU dsu1(n), dsu2(n); // create two instances of disjoint set union data structure + int cnt = 0; // count of number of edges added to graph + for (auto& v : edges) { // iterate through all edges + int t = 0; // type of edge added to graph + if (v[0] & 1) { // check if edge is of type 1 or 3 + if (dsu1.same_group(v[1], v[2])) // if vertices are already in the same group, skip + continue; + dsu1.join(v[1], v[2]); // join the vertices and decrease number of connected components + t |= 1; // set the type of edge + } + if (v[0] & 2) { // check if edge is of type 2 or 3 + if (dsu2.same_group(v[1], v[2])) // if vertices are already in the same group, skip + continue; + dsu2.join(v[1], v[2]); // join the vertices and decrease number of connected components + t |= 2; // set the type of edge + } + cnt += t > 0; // if an edge is added to the graph, increase the count + } + if (dsu1.cc != 1 || dsu2.cc != 1) // if the graph is not connected, return -1 + return -1; + return edges.size() - cnt; // return the number of edges removed from the graph +} diff --git a/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Omar_Sanad).cpp b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Omar_Sanad).cpp new file mode 100644 index 000000000..1bce67f7e --- /dev/null +++ b/04- April/30- Remove Max Number of Edges to Keep Graph Fully Traversable/30- Remove Max Number of Edges to Keep Graph Fully Traversable (Omar_Sanad).cpp @@ -0,0 +1,70 @@ +// author : Omar Sanad + +// DSU Structure +template < typename T = int > struct DSU { + vector < T > par, gr_sz; + T groups; + + // DSU constructor + DSU(int numNodes) { + groups = numNodes; + gr_sz.assign(numNodes + 1, 1), par.resize(numNodes + 1); + for(int i = 1; i <= numNodes; i++) par[i] = i; + } + + // operator = , to assign one dsu to another + DSU operator = (DSU& other) { + par = other.par; + gr_sz = other.gr_sz; + groups = other.groups; + return *this; + } + + T getRoot(int node) {return par[node] = (par[node] == node ? node : getRoot(par[node]));} + T get_size(int node) {return gr_sz[getRoot(node)];} + bool SameGr(int u, int v){return getRoot(u) == getRoot(v);} + + void combine(int a, int b) { + int root_of_a = getRoot(a), root_of_b = getRoot(b); + if(root_of_a == root_of_b) return; // They are already in the same group + if(gr_sz[root_of_a] < gr_sz[root_of_b]) swap(root_of_a, root_of_b); + gr_sz[root_of_a] += gr_sz[root_of_b], par[root_of_b] = root_of_a; + groups--; + } +}; + +class Solution { +public: + int maxNumEdgesToRemove(int n, vector>& edges) { + + // Declare the dsu that has the paths that both Alice and Bob can use + DSU du(n); + + // The number of used edges + int ans = 0; + + // use all edges of type 3 (both Alice and Bob can use), (the ones you need only) + for (auto &e : edges) + if (e.front() == 3 and not du.SameGr(e[1], e[2])) + ans++, du.combine(e[1], e[2]); + + + // Declare another two DSUs, one for Alice and the other one for Bob. + DSU Alice = du, Bob = du; + + // use the edges you need in the other two types + for (auto &e : edges) + if (e[0] == 1) { // Alice + if (not Alice.SameGr(e[1], e[2])) + ans++, Alice.combine(e[1], e[2]); + } + else if (e[0] == 2) { // Bob + if (not Bob.SameGr(e[1], e[2])) + ans++, Bob.combine(e[1], e[2]); + } + + // if Both Alice and Bob can fully traverse the graph + // return the number of deleted edges. + return Alice.groups == 1 and Bob.groups == 1 ? edges.size() - ans : -1; + } +};