Maximum Nodes removed to Keep the Graph Reachable
Last Updated :
05 Mar, 2024
You and your Friend are given an undirected graph having 3 types of edges. A graph is called Reachable if starting from any node, you and your friend can reach all other nodes. Print the maximum number of edges that you can remove in order for the graph to remain Reachable. or print -1.
- Type 1: could be traveled by you only
- Type 2: could be traveled by your friend only
- Type 3: could be traveled by both you and your friend
Examples:
Input: graph[type, u, v] = [[3, 1, 2], [3, 2, 3], [1, 1, 3], [1, 2, 4], [1, 1, 2], [2, 3, 4]], n = 4
Output: 2
Explanation: If we remove the two edges [1,1,2] and [1,1,3] Alice and Bob will still be able to traverse the graph. Any additional edge removal, beyond this point will not enable traversal. Hence the maximum number of edges we can remove is two.
Input: graph[type, u, v] = [[3, 2, 3], [1, 1, 2], [2, 3, 4]], n = 4
Output: -1
Explanation: In the given graph it is not possible for Alice to reach node 4 from any node and likewise for Bob to reach node 1. Therefore achieving traversal of the graph is impossible.
Approach: To solve the problem follow the below idea:
To solve this problem we utilize the union find data structure. This structure allows us to keep track of components, for each of the three types of edges (1, 2 and 3). Our algorithm proceeds by iterating through the edges in descending order of type. During each iteration we perform union operations. Keep count of the edges. The final result is obtained by subtracting the count of used edges from the number of edges, which represents the removal required to satisfy the disjoint set condition.
To solve the problem follow the below steps:
- Create a helper function called “find” that carries out the find operation within the union find data structure. This function returns the root element of a given elements set.
- Initialize a vector called “ds_both” to represent the disjoint set for type 3 edges. Each element within this vector is initially set to 1 as an indicator for a singleton set.
- Utilize a loop to iterate over all three types of edges (, from type 3 down to type 1).
- Within this loop create a disjoint set called “ds_one” for handling edges of the current type (excluding type 3).
- Iterate through all the edges. Perform union find operations based on their types. Increment our counter for each redundant edge encountered.
- Once you have processed type 3 edges you need to ensure that the graph is fully connected for each person (excluding type 3). If its not simply return 1.
Below is the C++ implementation of above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
int find(vector< int >& ds, int i)
{
return ds[i] < 0 ? i : ds[i] = find(ds, ds[i]);
}
int maxNumEdgesToRemove( int n, vector<vector< int > >& edges)
{
vector< int > ds_both(n + 1, -1);
int used = 0;
for ( int type = 3; type > 0; --type) {
auto ds_one = ds_both;
auto & ds = type == 3 ? ds_both : ds_one;
for ( auto & e : edges) {
if (e[0] == type) {
int i = find(ds, e[1]), j = find(ds, e[2]);
if (i != j) {
++used;
if (ds[j] < ds[i])
swap(i, j);
ds[i] += ds[j];
ds[j] = i;
}
}
}
if (type != 3 && ds[find(ds, 1)] != -n)
return -1;
}
return edges.size() - used;
}
int main()
{
int n = 4;
vector<vector< int > > edges
= { { 3, 1, 2 }, { 3, 2, 3 }, { 1, 1, 3 },
{ 1, 2, 4 }, { 1, 1, 2 }, { 2, 3, 4 } };
int result = maxNumEdgesToRemove(n, edges);
cout << "Result: " << result << endl;
return 0;
}
|
Java
import java.util.Arrays;
class GFG {
static int find( int [] ds, int i)
{
if (ds[i] < 0 )
return i;
return ds[i] = find(ds, ds[i]);
}
static int maxNumEdgesToRemove( int n, int [][] edges)
{
int [] ds_both = new int [n + 1 ];
Arrays.fill(ds_both, - 1 );
int used = 0 ;
for ( int type = 3 ; type > 0 ; --type) {
int [] ds_one = ds_both.clone();
int [] ds = type == 3 ? ds_both : ds_one;
for ( int [] e : edges) {
if (e[ 0 ] == type) {
int i = find(ds, e[ 1 ]),
j = find(ds, e[ 2 ]);
if (i != j) {
++used;
if (ds[j] < ds[i]) {
int t = i;
i = j;
j = t;
}
ds[i] += ds[j];
ds[j] = i;
}
}
}
if (type != 3 && ds[find(ds, 1 )] != -n)
return - 1 ;
}
return edges.length - used;
}
public static void main(String[] args)
{
int n = 4 ;
int [][] edges
= { { 3 , 1 , 2 }, { 3 , 2 , 3 }, { 1 , 1 , 3 },
{ 1 , 2 , 4 }, { 1 , 1 , 2 }, { 2 , 3 , 4 } };
int result = maxNumEdgesToRemove(n, edges);
System.out.println( "Result: " + result);
}
}
|
C#
using System;
class GFG {
static int Find( int [] ds, int i)
{
if (ds[i] < 0)
return i;
return ds[i] = Find(ds, ds[i]);
}
static int MaxNumEdgesToRemove( int n, int [][] edges)
{
int [] dsBoth = new int [n + 1];
Array.Fill(
dsBoth,
-1);
int used = 0;
for ( int type = 3; type > 0; --type) {
int [] dsOne
= ( int [])dsBoth
.Clone();
int [] ds
= type == 3
? dsBoth
: dsOne;
foreach ( int [] e in edges)
{
if (e[0] == type)
{
int i = Find(ds, e[1]);
int j = Find(ds, e[2]);
if (i != j)
{
++used;
if (ds[j]
< ds[i])
{
int t = i;
i = j;
j = t;
}
ds[i]
+= ds[j];
ds[j]
= i;
}
}
}
if (type != 3 && ds[Find(ds, 1)] != -n)
return -1;
}
return edges.Length - used;
}
public static void Main( string [] args)
{
int n = 4;
int [][] edges = new int [][] {
new int [] { 3, 1, 2 }, new int [] { 3, 2, 3 },
new int [] { 1, 1, 3 }, new int [] { 1, 2, 4 },
new int [] { 1, 1, 2 }, new int [] { 2, 3, 4 }
};
int result = MaxNumEdgesToRemove(n, edges);
Console.WriteLine( "Result: " + result);
}
}
|
Javascript
function find(ds, i) {
if (ds[i] < 0)
return i;
return ds[i] = find(ds, ds[i]);
}
function maxNumEdgesToRemove(n, edges) {
let ds_both = new Array(n + 1).fill(-1);
let used = 0;
for (let type = 3; type > 0; --type) {
let ds_one = [...ds_both];
let ds = type === 3 ? ds_both : ds_one;
for (let e of edges) {
if (e[0] === type) {
let i = find(ds, e[1]),
j = find(ds, e[2]);
if (i !== j) {
++used;
if (ds[j] < ds[i]) {
let t = i;
i = j;
j = t;
}
ds[i] += ds[j];
ds[j] = i;
}
}
}
if (type !== 3 && ds[find(ds, 1)] !== -n)
return -1;
}
return edges.length - used;
}
let n = 4;
let edges = [
[3, 1, 2],
[3, 2, 3],
[1, 1, 3],
[1, 2, 4],
[1, 1, 2],
[2, 3, 4]
];
let result = maxNumEdgesToRemove(n, edges);
console.log( "Result: " + result);
|
Python3
def find(ds, i):
return i if ds[i] < 0 else find(ds, ds[i])
def max_num_edges_to_remove(n, edges):
ds_both = [ - 1 ] * (n + 1 )
used = 0
for type in range ( 3 , 0 , - 1 ):
ds_one = list (ds_both)
ds = ds_both if type = = 3 else ds_one
for e in edges:
if e[ 0 ] = = type :
i, j = find(ds, e[ 1 ]), find(ds, e[ 2 ])
if i ! = j:
used + = 1
if ds[j] < ds[i]:
i, j = j, i
ds[i] + = ds[j]
ds[j] = i
if type ! = 3 and ds[find(ds, 1 )] ! = - n:
return - 1
return len (edges) - used
n = 4
edges = [[ 3 , 1 , 2 ], [ 3 , 2 , 3 ], [ 1 , 1 , 3 ], [ 1 , 2 , 4 ], [ 1 , 1 , 2 ], [ 2 , 3 , 4 ]]
result = max_num_edges_to_remove(n, edges)
print ( "Result:" , result)
|
Time Complexity: O(E * α(V))Where E is the number of edges (E), and the inverse Ackermann function (α) and V is the number of nodes (V). It can be considered constant.
Auxiliary Space: O(V) where is the number of nodes (V).
Share your thoughts in the comments
Please Login to comment...