Alice and Bob have an undirected graph of n
nodes and three types of edges:
Given an array edges
where edges[i] = [type_i, u_i, v_i]
represents a bidirectional edge of type type_i
between nodes u_i
and v_i
, find the maximum number of edges you can remove so that after removing the edges, the graph can still be fully traversed by both Alice and Bob. The graph is fully traversed by Alice and Bob if starting from any node, they can reach all other nodes.
Return the maximum number of edges you can remove, or return -1
if Alice and Bob cannot fully traverse the graph.
Example 1:
Input: n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
Output: 2
Explanation: If we remove the 2 edges [1,1,2] and [1,1,3]. The graph will still be fully traversable by Alice and Bob. Removing any additional edge will not make it so. So the maximum number of edges we can remove is 2.
Example 2:
Input: n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
Output: 0
Explanation: Notice that removing any edge will not make the graph fully traversable by Alice and Bob.
Example 3:
Input: n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
Output: -1
Explanation: In the current graph, Alice cannot reach node 4 from the other nodes. Likewise, Bob cannot reach 1. Therefore it's impossible to make the graph fully traversable.
Can you describe an algorithm with optimal runtime to solve this problem?
You are given an undirected graph with n
nodes and three types of edges:
Given edges
array where edges[i] = [type_i, u_i, v_i]
, find the maximum number of edges you can remove such that after removing them, both Alice and Bob can fully traverse the graph. Return the maximum number of edges that can be removed or -1 if Alice and Bob cannot fully traverse the graph.
The most basic approach would be to try every possible combination of edge removals and, for each combination, check if both Alice and Bob can fully traverse the graph. This is a brute-force strategy.
Complexity:
E
is the number of edges and V
is the number of vertices. The 2E comes from generating all subsets. The (V+E) comes from the DFS/BFS operation to determine connectivity.The optimal solution utilizes the concept of Disjoint Set Union (DSU) (also known as Union-Find) to efficiently determine connected components for Alice and Bob.
Algorithm:
n
nodes.edges
and process type 3 edges:
edges
again and process type 1 (Alice-only) edges:
edges
again and process type 2 (Bob-only) edges:
total_edges - kept_edges
Code (Python):
class DSU:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x]) # Path compression
return self.parent[x]
def union(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x != root_y:
if self.rank[root_x] < self.rank[root_y]:
self.parent[root_x] = root_y
elif self.rank[root_x] > self.rank[root_y]:
self.parent[root_y] = root_x
else:
self.parent[root_y] = root_x
self.rank[root_x] += 1
return True
return False
def max_removable_edges(n: int, edges: list[list[int]]) -> int:
alice_dsu = DSU(n)
bob_dsu = DSU(n)
kept_edges = 0
total_edges = len(edges)
# Process type 3 edges first
for type, u, v in edges:
if type == 3:
if alice_dsu.union(u - 1, v - 1):
bob_dsu.union(u - 1, v - 1)
kept_edges += 1
# Process type 1 edges (Alice-only)
for type, u, v in edges:
if type == 1:
if alice_dsu.union(u - 1, v - 1):
kept_edges += 1
# Process type 2 edges (Bob-only)
for type, u, v in edges:
if type == 2:
if bob_dsu.union(u - 1, v - 1):
kept_edges += 1
# Check if Alice and Bob can fully traverse
alice_components = 0
bob_components = 0
for i in range(n):
if alice_dsu.find(i) == i:
alice_components += 1
if bob_dsu.find(i) == i:
bob_components += 1
if alice_components != 1 or bob_components != 1:
return -1
return total_edges - kept_edges
Complexity:
E
is the number of edges, N
is the number of nodes, and α
is the inverse Ackermann function, which grows extremely slowly and can be considered almost constant for practical input sizes. The dominant operations are the find
and union
operations of the DSU, which have near-constant time complexity with path compression and union by rank.Edge Cases:
-1
.n
is 1, any number of edges can be removed since it is already fully traversed. The DSU implementation handles this case without issue.edges
is empty, then if n
is 1 the return value is 0. If n
is greater than 1, the return value is -1.