Given an undirected graph of N node, where nodes are numbered from 1 to N, and an array of edges, where edges[i] = {edgeType, u, v} and two persons A and B are moving in it. Each edge type indicates different things.
- edgeType = 0 indicates that only A can travel on that edge from node u to v.
- edgeType = 1 indicates that only B can travel on that edge from node u to v.
- edgeType = 2, then both persons can travel on that edge.
The task is to delete the maximum number of edges such that both persons still travel on all the nodes starting from any node or return -1 if both persons cannot fully traverse the graph.
Examples:
Input: N = 4, edges = { { 0, 1, 2 }, {0, 3, 4}, {1, 1, 2}, {1, 2, 4}, { 2, 1, 2 }, { 2, 1, 3 } } Output: 2 Explanation: Remove an edge between node 1 and node 2 which have edgeType = 0 Remove an edge between node 1 and node 2 which have edgeType = 1 The final node remaining is traversable by both the person.
 The above graph
Input: N = 2, edges = { { 0, 1, 2 }, { 1, 1, 2 }, { 2, 1, 2 } } Output: 2
Sort the edges[] on the basis of edgeType which is traversable by both. Use DSU for keeping track of number of connected component for both the person individually and initially assign count of connected component to N as we’ll assume every node an individual component.
- Try to connect edges which are traversable in their DSU, if edges are not redundant then add that edge and reduce the number of connected component by 1 for that person. Otherwise, remove that edge.
- Finally check if any one have number of connected component greater than 1, means that person can’t traverse every node. So, return -1. Otherwise, return count of remove.
Follow the steps below to implement the above idea:
- Sort on the basis of that edge which is traversable by both person
- Initialize a parentA[] for person A, parentB[] for person B
- Initialize a rankA[] for person A, rankB[] for person B
- Initially, every node is its own parent and make its rank = 1.
- Create variable connectedComponentA and connectedComponentB to count the number of connected components where A and B can travel respectively.
- Create a remove variable to keep track of how many redundant nodes can be removed.
- Iterate over all the edges:
- Connect that node with edges first which is traversable by both, (i.e, edgeType = 2)
- Try to merge node into DSU for person A.
- Try to merge node into DSU for person B.
- If there is a merge of nodes in DSU for person A.
- Decrement connectedComponentA by 1.
- If there is a merge of nodes in DSU for person B.
- Decrement connectedComponentB by 1.
- If there is no merge of nodes in both the DSU
- This edge is redundant. So, increment remove.
- For edges with edgeType=0, try to merge node into DSU for person A
- If there is a merge of nodes in DSU for person A.
- Decrement connectedComponentA by 1.
- If there is no merge of nodes in person A’s DSU.
- This edge is redundant. So, increment remove.
- For edges with edgeType = 1, try to merge node into DSU for person B
- If there is a merge of nodes in DSU for person B.
- Decrement of connectedComponentB by 1
- If there is no merge of nodes in person B’s DSU
- This edge is redundant. So, increment remove.
- Finally, check if anyone’s connected Component is not 1:
- Then, there is no way to travel on all the nodes by both people. So, return -1
- Otherwise, return the remove count.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
bool static cmp(vector< int >& a, vector< int >& b)
{
return a[0] > b[0];
}
int find( int x, vector< int >& parent)
{
if (parent[x] == x)
return x;
return parent[x] = find(parent[x], parent);
}
bool union1( int x, int y, vector< int >& parent,
vector< int >& rank)
{
int lx = find(x, parent);
int ly = find(y, parent);
if (lx != ly) {
if (rank[lx] > rank[ly]) {
parent[ly] = lx;
}
else if (rank[lx] < rank[ly]) {
parent[lx] = ly;
}
else {
parent[lx] = ly;
rank[ly] += 1;
}
return true ;
}
return false ;
}
int removeMaxEdges( int n, vector<vector< int > >& edges)
{
int n1 = n + 1;
sort(edges.begin(), edges.end(), cmp);
vector< int > parentA(n1), parentB(n1), rankA(n1),
rankB(n1);
for ( int i = 1; i <= n; i++) {
parentA[i] = i;
parentB[i] = i;
rankA[i] = 1;
rankB[i] = 1;
}
int connectedComponentA = n, connectedComponentB = n,
remove = 0;
for ( auto i : edges) {
if (i[0] == 2) {
bool mergeA
= union1(i[1], i[2], parentA, rankA);
bool mergeB
= union1(i[1], i[2], parentB, rankB);
if (mergeA) {
connectedComponentA--;
}
if (mergeB) {
connectedComponentB--;
}
if (mergeA == false && mergeB == false ) {
remove ++;
}
}
else if (i[0] == 1) {
bool mergeA
= union1(i[1], i[2], parentA, rankA);
if (mergeA) {
connectedComponentA--;
}
if (mergeA == false ) {
remove ++;
}
}
else {
bool mergeB
= union1(i[1], i[2], parentB, rankB);
if (mergeB) {
connectedComponentB--;
}
if (mergeB == false ) {
remove ++;
}
}
}
if (connectedComponentA != 1
|| connectedComponentB != 1) {
return -1;
}
return remove ;
}
int main()
{
int N = 4;
vector<vector< int > > edges
= { { 0, 1, 2 }, { 0, 3, 4 }, { 1, 1, 2 }, { 1, 2, 4 }, { 2, 1, 2 }, { 2, 1, 3 } };
cout << removeMaxEdges(N, edges);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
public static int find( int x, List<Integer> parent)
{
if (parent.get(x) == x)
return x;
parent.set(x, find(parent.get(x), parent));
return parent.get(x);
}
public static boolean union1( int x, int y,
List<Integer> parent,
List<Integer> rank)
{
int lx = find(x, parent);
int ly = find(y, parent);
if (lx != ly) {
if (rank.get(lx) > rank.get(ly)) {
parent.set(ly, lx);
}
else if (rank.get(lx) < rank.get(ly)) {
parent.set(lx, ly);
}
else {
parent.set(lx, ly);
rank.set(ly, rank.get(ly) + 1 );
}
return true ;
}
return false ;
}
public static int
removeMaxEdges( int n, List<List<Integer> > edges)
{
int n1 = n + 1 ;
Collections.sort(
edges, new Comparator<List<Integer> >() {
@Override
public int compare( final List<Integer> a,
List<Integer> b)
{
if (a.get( 0 ) > b.get( 0 ))
return - 1 ;
return 1 ;
}
});
List<Integer> parentA = new ArrayList<Integer>();
List<Integer> parentB = new ArrayList<Integer>();
List<Integer> rankA = new ArrayList<Integer>();
List<Integer> rankB = new ArrayList<Integer>();
for ( int i = 1 ; i <= n1; i++) {
parentA.add( 0 );
parentB.add( 0 );
rankA.add( 0 );
rankB.add( 0 );
}
for ( int i = 1 ; i <= n; i++) {
parentA.set(i, i);
parentB.set(i, i);
rankA.set(i, 1 );
rankB.set(i, 1 );
}
int connectedComponentA = n,
connectedComponentB = n, remove = 0 ;
for ( int j = 0 ; j < edges.size(); j++) {
List<Integer> i = edges.get(j);
if (i.get( 0 ) == 2 ) {
boolean mergeA = union1(i.get( 1 ), i.get( 2 ),
parentA, rankA);
boolean mergeB = union1(i.get( 1 ), i.get( 2 ),
parentB, rankB);
if (mergeA) {
connectedComponentA--;
}
if (mergeB) {
connectedComponentB--;
}
if (mergeA == false && mergeB == false ) {
remove++;
}
}
else if (i.get( 0 ) == 1 ) {
boolean mergeA = union1(i.get( 1 ), i.get( 2 ),
parentA, rankA);
if (mergeA) {
connectedComponentA--;
}
if (mergeA == false ) {
remove++;
}
}
else {
boolean mergeB = union1(i.get( 1 ), i.get( 2 ),
parentB, rankB);
if (mergeB) {
connectedComponentB--;
}
if (mergeB == false ) {
remove++;
}
}
}
if (connectedComponentA != 1
|| connectedComponentB != 1 ) {
return - 1 ;
}
return remove;
}
public static void main(String[] args)
{
int N = 4 ;
List<List<Integer> > edges
= new ArrayList<List<Integer> >();
List<Integer> a = new ArrayList<Integer>();
a.add( 0 );
a.add( 1 );
a.add( 2 );
edges.add(a);
List<Integer> b = new ArrayList<Integer>();
b.add( 0 );
b.add( 3 );
b.add( 4 );
edges.add(b);
List<Integer> c = new ArrayList<Integer>();
c.add( 1 );
c.add( 1 );
c.add( 2 );
edges.add(c);
List<Integer> d = new ArrayList<Integer>();
d.add( 1 );
d.add( 2 );
d.add( 4 );
edges.add(d);
List<Integer> e = new ArrayList<Integer>();
e.add( 2 );
e.add( 1 );
e.add( 2 );
edges.add(e);
List<Integer> f = new ArrayList<Integer>();
f.add( 2 );
f.add( 1 );
f.add( 3 );
edges.add(f);
System.out.println(removeMaxEdges(N, edges));
}
}
|
C#
using System;
using System.Collections;
using System.Collections.Generic;
public class GFG {
public static int cmp(List< int > a, List< int > b)
{
if (a[0] > b[0])
return -1;
return 1;
}
public static int find( int x, List< int > parent)
{
if (parent[x] == x)
return x;
return parent[x] = find(parent[x], parent);
}
public static bool
union1( int x, int y, List< int > parent, List< int > rank)
{
int lx = find(x, parent);
int ly = find(y, parent);
if (lx != ly) {
if (rank[lx] > rank[ly]) {
parent[ly] = lx;
}
else if (rank[lx] < rank[ly]) {
parent[lx] = ly;
}
else {
parent[lx] = ly;
rank[ly] += 1;
}
return true ;
}
return false ;
}
public static int removeMaxEdges( int n,
List<List< int > > edges)
{
int n1 = n + 1;
edges.Sort(cmp);
List< int > parentA = new List< int >();
List< int > parentB = new List< int >();
List< int > rankA = new List< int >();
List< int > rankB = new List< int >();
for ( int i = 0; i < n1; i++) {
parentA.Add(0);
parentB.Add(0);
rankA.Add(0);
rankB.Add(0);
}
for ( int i = 1; i <= n; i++) {
parentA[i] = i;
parentB[i] = i;
rankA[i] = 1;
rankB[i] = 1;
}
int connectedComponentA = n,
connectedComponentB = n, remove = 0;
for ( int i = 0; i < edges.Count; i++) {
if (edges[i][0] == 2) {
bool mergeA
= union1(edges[i][1], edges[i][2],
parentA, rankA);
bool mergeB
= union1(edges[i][1], edges[i][2],
parentB, rankB);
if (mergeA) {
connectedComponentA--;
}
if (mergeB) {
connectedComponentB--;
}
if (mergeA == false && mergeB == false ) {
remove++;
}
}
else if (edges[i][0] == 1) {
bool mergeA
= union1(edges[i][1], edges[i][2],
parentA, rankA);
if (mergeA) {
connectedComponentA--;
}
if (mergeA == false ) {
remove++;
}
}
else {
bool mergeB
= union1(edges[i][1], edges[i][2],
parentB, rankB);
if (mergeB) {
connectedComponentB--;
}
if (mergeB == false ) {
remove++;
}
}
}
if (connectedComponentA != 1
|| connectedComponentB != 1) {
return -1;
}
return remove;
}
static public void Main()
{
int N = 4;
List<List< int > > edges = new List<List< int > >{
new List< int >{ 0, 1, 2 },
new List< int >{ 0, 3, 4 },
new List< int >{ 1, 1, 2 },
new List< int >{ 1, 2, 4 },
new List< int >{ 2, 1, 2 },
new List< int >{ 2, 1, 3 }
};
Console.WriteLine(removeMaxEdges(N, edges));
}
}
|
Javascript
function find(x, parent)
{
if (parent[x] == x)
return x;
return parent[x] = find(parent[x], parent);
}
function union1(x, y, parent, rank)
{
let lx = find(x, parent);
let ly = find(y, parent);
if (lx != ly) {
if (rank[lx] > rank[ly]) {
parent[ly] = lx;
}
else if (rank[lx] < rank[ly]) {
parent[lx] = ly;
}
else {
parent[lx] = ly;
rank[ly] += 1;
}
return true ;
}
return false ;
}
function removeMaxEdges(n, edges)
{
let n1 = n + 1;
edges.sort( function (a, b){ return b[0] - a[0] });
let parentA = new Array(n1), parentB = new Array(n1),
rankA = new Array(n1);
rankB = new Array(n1);
for (let i = 1; i <= n; i++) {
parentA[i] = i;
parentB[i] = i;
rankA[i] = 1;
rankB[i] = 1;
}
let connectedComponentA = n, connectedComponentB = n,
remove = 0;
for (let i of edges) {
if (i[0] == 2) {
let mergeA = union1(i[1], i[2], parentA, rankA);
let mergeB = union1(i[1], i[2], parentB, rankB);
if (mergeA) {
connectedComponentA--;
}
if (mergeB) {
connectedComponentB--;
}
if (mergeA == false && mergeB == false ) {
remove++;
}
}
else if (i[0] == 1) {
let mergeA = union1(i[1], i[2], parentA, rankA);
if (mergeA) {
connectedComponentA--;
}
if (mergeA == false ) {
remove++;
}
}
else {
let mergeB = union1(i[1], i[2], parentB, rankB);
if (mergeB) {
connectedComponentB--;
}
if (mergeB == false ) {
remove++;
}
}
}
if (connectedComponentA != 1
|| connectedComponentB != 1) {
return -1;
}
return remove;
}
let N = 4;
let edges = [
[ 0, 1, 2 ], [ 0, 3, 4 ], [ 1, 1, 2 ], [ 1, 2, 4 ],
[ 2, 1, 2 ], [ 2, 1, 3 ]
];
console.log(removeMaxEdges(N, edges));
|
Python3
from functools import cmp_to_key
def cmp (a, b):
return a[ 0 ] > b[ 0 ]
def find(x, parent):
if parent[x] = = x:
return x
parent[x] = find(parent[x], parent)
return parent[x]
def union1(x, y, parent, rank):
lx = find(x, parent)
ly = find(y, parent)
if lx ! = ly:
if rank[lx] > rank[ly]:
parent[ly] = lx
elif rank[lx] < rank[ly]:
parent[lx] = ly
else :
parent[lx] = ly
rank[ly] + = 1
return True
return False
def removeMaxEdges(n, edges):
n1 = n + 1
edges.sort(key = cmp_to_key( cmp ))
parentA, parentB = [ 0 ] * n1, [ 0 ] * n1
rankA, rankB = [ 0 ] * n1, [ 0 ] * n1
for i in range ( 1 , n1):
parentA[i] = i
parentB[i] = i
rankA[i] = 1
rankB[i] = 1
connectedComponentA, connectedComponentB = n, n
remove = 1
for i in edges:
if i[ 0 ] = = 2 :
mergeA = union1(i[ 1 ], i[ 2 ], parentA, rankA)
mergeB = union1(i[ 1 ], i[ 2 ], parentB, rankB)
if mergeA:
connectedComponentA - = 1
if mergeB:
connectedComponentB - = 1
if not mergeA and not mergeB:
remove + = 1
elif i[ 0 ] = = 1 :
mergeA = union1(i[ 1 ], i[ 2 ], parentA, rankA)
if mergeA:
connectedComponentA - = 1
if not mergeA:
remove + = 1
else :
mergeB = union1(i[ 1 ], i[ 2 ], parentB, rankB)
if mergeB:
connectedComponentB - = 1
if not mergeB:
remove + = 1
if connectedComponentA ! = 1 or connectedComponentB ! = 1 :
return - 1
return remove
if __name__ = = '__main__' :
N = 4
edges = [[ 0 , 1 , 2 ], [ 0 , 3 , 4 ], [ 1 , 1 , 2 ], [ 1 , 2 , 4 ], [ 2 , 1 , 2 ], [ 2 , 1 , 3 ]]
print (removeMaxEdges(N, edges))
|
Time Complexity: O(E * log(N) + E), where E, and N are the number of edges and number of nodes respectively. Auxiliary Space: O(N)
|