Skip to content

Commit

Permalink
Merge branch '7oSkaaa:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
AhmedGamal2212 committed May 1, 2023
2 parents 0f4a83e + d7b3bb9 commit b51a31e
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<int> 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<vector<int>>& 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;
}
};
Original file line number Diff line number Diff line change
@@ -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<int> 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<vector<int>>& 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
}
Original file line number Diff line number Diff line change
@@ -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<vector<int>>& 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;
}
};

0 comments on commit b51a31e

Please sign in to comment.