
Problem Statement
The task involves determining the number of pairs of nodes in an undirected graph that are unreachable from one another. An integer n
represents the total number of nodes in the graph, which are numerically labeled from 0 to n-1
. The graph's edges are provided as a list of pairs, each pair [ai, bi]
indicating an undirected edge between nodes ai
and bi
. The primary goal is to compute how many distinct pairs of nodes do not have a path connecting them.
Examples
Example 1
Input:
n = 3, edges = [[0,1],[0,2],[1,2]]
Output:
0
Explanation:
There are no pairs of nodes that are unreachable from each other. Therefore, we return 0.
Example 2
Input:
n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
Output:
14
Explanation:
There are 14 pairs of nodes that are unreachable from each other: [[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]. Therefore, we return 14.
Constraints
1 <= n <= 105
0 <= edges.length <= 2 * 105
edges[i].length == 2
0 <= ai, bi < n
ai != bi
- There are no repeated edges.
Approach and Intuition
Given the problem's nature, let's break down the method to solve it through the following steps:
Interpret the graph structure from the edges.
- Construct an adjacency list to represent the graph, which will efficiently store all nodes and their respective connections.
Identify connected components.
- Use Depth First Search (DFS) or Breadth First Search (BFS) to explore the graph.
- Start from any unvisited node and visit all reachable nodes to form a connected component.
- Keep track of the nodes involved in each component.
Calculate the unreachable node pairs.
- First, for each component, calculate the possible pairs within the component itself, ensuring that these pairs are reachable.
- Compute the total possible pairs of nodes which is given by the formula: C(n, 2) = n * (n - 1) / 2, where
n
is the number of nodes. - The number of unreachable pairs can be found by subtracting the reachable pairs in all components from the total pairs.
Consider different scenarios:
- All nodes connected: If all nodes are part of a single connected component, then every node is reachable from every other node, resulting in zero unreachable pairs.
- Multiple connected components: If the graph contains multiple disjoint components, then nodes from different components will form unreachable pairs.
By reviewing the examples provided:
- In Example 1, all three nodes are connected hence there are no unreachable pairs.
- In Example 2, the graph is fragmented into different disjoint components, leading to 14 unreachable pairs calculated by checking inter-component connections.
Solutions
- C++
- Java
class DisjointSetUnion {
private:
vector<int> parent, size;
public:
DisjointSetUnion(int count) {
parent.resize(count);
size.resize(count, 0);
for (int i = 0; i < count; i++) {
parent[i] = i;
}
}
int findParent(int node) {
if (parent[node] != node) parent[node] = findParent(parent[node]);
return parent[node];
}
void unite(int x, int y) {
int rootX = findParent(x), rootY = findParent(y);
if (rootX == rootY) {
return;
} else if (size[rootX] < size[rootY]) {
parent[rootX] = rootY;
} else if (size[rootX] > size[rootY]) {
parent[rootY] = rootX;
} else {
parent[rootY] = rootX;
size[rootX]++;
}
}
};
class Solution {
public:
long long calculatePairs(int m, vector<vector<int>>& relations) {
DisjointSetUnion dsu(m);
for (auto relation : relations) {
dsu.unite(relation[0], relation[1]);
}
unordered_map<int, int> clusterCount;
for (int i = 0; i < m; i++) {
clusterCount[dsu.findParent(i)]++;
}
long long paths = 0;
long long leftoverNodes = m;
for (auto cluster : clusterCount) {
int countInCluster = cluster.second;
paths += countInCluster * (leftoverNodes - countInCluster);
leftoverNodes -= countInCluster;
}
return paths;
}
};
This solution addresses the problem of counting unreachable pairs of nodes in an undirected graph using C++. The primary approach involves utilizing a Disjoint Set Union (DSU) data structure to manage and analyze node connectivity effectively.
Start by defining a
DisjointSetUnion
class to encapsulate the union-find algorithm functionality:- Initialize each node to be its own parent and set an initial size.
- Provide a method to find the representative parent for a given node, implementing path compression for efficiency.
- Include a method to unite two nodes. This method links nodes by size, ensuring that smaller trees get attached under larger ones, maintaining a balanced tree structure.
Implement the primary
Solution
class:- Define the
calculatePairs
function which uses instances ofDisjointSetUnion
. - Loop through given node relations and unite nodes according to provided edges.
- Count the size of each cluster formed in the DSU by finding the parent for each node and accumulating the count in a hash map.
- Calculate the number of unreachable pairs by examining the sizes of these clusters:
- For each cluster, compute potential pair combinations with nodes not in the current cluster.
- Subtract the nodes in the current cluster from the total to avoid recounting.
- Define the
This approach ensures that each pair is considered exactly once, yielding an efficient solution to the problem. The DSU helps manage connected components and makes it feasible to total the unreachable pairs by systematically considering the contribution of each cluster independently.
class DisjointSet {
int[] leader;
int[] treeSize;
public DisjointSet(int capacity) {
leader = new int[capacity];
for (int i = 0; i < capacity; i++)
leader[i] = i;
treeSize = new int[capacity];
}
public int findRoot(int node) {
if (leader[node] != node)
leader[node] = findRoot(leader[node]);
return leader[node];
}
public void unite(int node1, int node2) {
int root1 = findRoot(node1), root2 = findRoot(node2);
if (root1 == root2) {
return;
} else if (treeSize[root1] < treeSize[root2]) {
leader[root1] = root2;
} else if (treeSize[root1] > treeSize[root2]) {
leader[root2] = root1;
} else {
leader[root2] = root1;
treeSize[root1]++;
}
}
}
class Solution {
public long countPairs(int n, int[][] edges) {
DisjointSet dsu = new DisjointSet(n);
for(int[] edge: edges) {
dsu.unite(edge[0], edge[1]);
}
Map<Integer, Integer> sizeMap = new HashMap<>();
for(int i = 0; i < n; i++) {
int leader = dsu.findRoot(i);
if(sizeMap.containsKey(leader)) {
sizeMap.put(leader, sizeMap.get(leader) + 1);
} else {
sizeMap.put(leader, 1);
}
}
long result = 0;
long remainingNodes = n;
for (int size : sizeMap.values()) {
result += size * (remainingNodes - size);
remainingNodes -= size;
}
return result;
}
}
The provided Java code efficiently calculates the number of pairs of nodes in an undirected graph that are not reachable from each other. This method utilizes a DisjointSet (Union-Find) data structure to manage and merge sets of nodes, allowing it to keep track of which nodes are connected.
The
DisjointSet
class manages the connectivity information:- It contains two arrays,
leader
andtreeSize
. Theleader
array keeps track of the root of each node, facilitating the path compression technique during the find operation, which helps in optimizing the union operation by attaching smaller trees under the root of the larger trees, stored intreeSize
. - The
findRoot
function recursively finds the representative leader of a node, employing path compression for efficiency. - The
unite
function merges the sets containing two nodes. If the nodes are already in the same set, it does nothing; otherwise, it attaches the smaller tree under the larger tree, updating the tree size as necessary.
- It contains two arrays,
The
Solution
class contains the methodcountPairs
responsible for computing the count of unreachable pairs.- It initializes the DisjointSet with
n
nodes. - For each edge given, it merges the sets of the two connected nodes.
- After all unions, it calculates the size of each connected component using a HashMap
sizeMap
. - To find the number of unreachable pairs, iterate through each component size. For each component, calculate the pairs that can be formed with nodes not in the current component and subtract these from the total count.
- It initializes the DisjointSet with
This approach minimizes direct combinatorial calculations for each node pair, leading to an efficient solution to the problem using graph theory and the Disjoint Set data structure. The result from the function represents the count of pairs that cannot communicate directly or indirectly through given edges.
No comments yet.