Given an undirected graph with V vertices. Two vertices u and v belong to a single province if there is a path from u to v or v to u. Find the number of provinces. The graph is given as an n x n matrix adj where adj[i][j] = 1 if the ith city and the jth city are directly connected, and adj[i][j] = 0 otherwise.
A province is a group of directly or indirectly connected cities and no other cities outside of the group.
Input: adj=[ [1, 0, 0, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1] ]
Output: 2
Explanation:In this graph, there are two provinces: [1, 4] and [2, 3]. City 1 and city 4 have a path between them, and city 2 and city 3 also have a path between them. There is no path between any city in province 1 and any city in province 2.
Input: adj= [ [1, 0, 1], [0, 1, 0], [1, 0, 1] ]
Output: 2
Explanation: The graph clearly has 2 Provinces [1,3] and [2]. As city 1 and city 3 has a path between them they belong to a single province. City 2 has no path to city 1 or city 3 hence it belongs to another province.
Input: adj= [ [1, 1], [1, 1] ]
A province is like a group of directly or indirectly connected cities and no other cities outside of the group. Every city in a province can be visited from every other city in the same province.
To solve this problem, all the cities and their connections can be explored to identify these groups.
For this, the traversal techniques BFS and DFS can be used and every time, we had to start from a new city, a new group of cities is explored.
#include <bits/stdc++.h>
using namespace std;
class Solution {
private:
// Function for BFS traversal
void bfs(int node, vector<int> adjLs[], int vis[]) {
// Mark the node as visited
vis[node] = 1;
// Queue required for BFS traversal
queue <int> q;
// To start traversal from node
q.push(node);
/* Keep on traversing till
the queue is not empty */
while(!q.empty()) {
// Get the node
int i = q.front();
q.pop();
// Traverse its unvisited neighbours
for(auto adjNodes: adjLs[i]) {
if(vis[adjNodes] != 1) {
// Mark the node as visited
vis[adjNodes] = 1;
// Add the node to queue
q.push(adjNodes);
}
}
}
}
// Function for DFS traversal
void dfs(int node, vector<int> adjLs[], int vis[]) {
// Mark the node as visited
vis[node] = 1;
// Traverse its unvisited neighbours
for(auto it: adjLs[node]) {
if(!vis[it]) {
// Recursively perform DFS
dfs(it, adjLs, vis);
}
}
}
public:
/* Function to find the number of
provinces in the given graph */
int numProvinces(vector<vector<int>> adj) {
// Variable to store number of nodes
int V = adj.size();
// To store adjacency list
vector<int> adjLs[V];
// Convert adjacency matrix to adjacency list
for(int i=0; i < V; i++) {
for(int j=0; j < V; j++) {
// self nodes are not considered
if(adj[i][j] == 1 && i != j) {
adjLs[i].push_back(j);
adjLs[j].push_back(i);
}
}
}
// Visited array
int vis[V] = {0};
// Variable to store number of provinces
int cnt = 0;
// Start Traversal
for(int i=0; i < V; i++) {
// If the node is not visited
if(!vis[i]) {
// Increment counter
cnt++;
// Start traversal from current node
bfs(i, adjLs, vis);
//dfs(i, adjLs, vis);
}
}
// Return the count
return cnt;
}
};
int main() {
vector<vector<int>> adj =
{
{1, 0, 0, 1},
{0, 1, 1, 0},
{0, 1, 1, 0},
{1, 0, 0, 1}
};
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to find the
provinces in the given graph */
int ans = sol.numProvinces(adj);
cout << "The number of provinces in the given graph is: " << ans;
return 0;
}
import java.util.*;
class Solution {
// Function for BFS traversal
private void bfs(int node, List<Integer> adjLs[], boolean[] vis) {
// Mark the node as visited
vis[node] = true;
// Queue required for BFS traversal
Queue<Integer> q = new LinkedList<>();
// To start traversal from node
q.add(node);
/* Keep on traversing till
the queue is not empty */
while (!q.isEmpty()) {
// Get the node
int i = q.poll();
// Traverse its unvisited neighbours
for (int adjNodes : adjLs[i]) {
if (!vis[adjNodes]) {
// Mark the node as visited
vis[adjNodes] = true;
// Add the node to queue
q.add(adjNodes);
}
}
}
}
// Function for DFS traversal
private void dfs(int node, List<Integer> adjLs[], boolean[] vis) {
// Mark the node as visited
vis[node] = true;
// Traverse its unvisited neighbours
for (int it : adjLs[node]) {
if (!vis[it]) {
// Recursively perform DFS
dfs(it, adjLs, vis);
}
}
}
/* Function to find the number of
provinces in the given graph */
public int numProvinces(int[][] adj) {
// Variable to store number of nodes
int V = adj.length;
// To store adjacency list
List<Integer>[] adjLs = new ArrayList[V];
for (int i = 0; i < V; i++) {
adjLs[i] = new ArrayList<>();
}
// Convert adjacency matrix to adjacency list
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
// self nodes are not considered
if (adj[i][j] == 1 && i != j) {
adjLs[i].add(j);
adjLs[j].add(i);
}
}
}
// Visited array
boolean[] vis = new boolean[V];
// Variable to store number of provinces
int cnt = 0;
// Start Traversal
for (int i = 0; i < V; i++) {
// If the node is not visited
if (!vis[i]) {
// Increment counter
cnt++;
// Start traversal from current node
bfs(i, adjLs, vis);
//dfs(i, adjLs, vis);
}
}
// Return the count
return cnt;
}
public static void main(String[] args) {
int[][] adj = {
{1, 0, 0, 1},
{0, 1, 1, 0},
{0, 1, 1, 0},
{1, 0, 0, 1}
};
/* Creating an instance of
Solution class */
Solution sol = new Solution();
/* Function call to find the
provinces in the given graph */
int ans = sol.numProvinces(adj);
System.out.println("The number of provinces in the given graph is: " + ans);
}
}
from collections import deque
class Solution:
# Function for BFS traversal
def bfs(self, node, adjLs, vis):
# Mark the node as visited
vis[node] = 1
# Queue required for BFS traversal
q = deque()
# To start traversal from node
q.append(node)
# Keep on traversing till
# the queue is not empty
while q:
# Get the node
i = q.popleft()
# Traverse its unvisited neighbours
for adjNodes in adjLs[i]:
if vis[adjNodes] != 1:
# Mark the node as visited
vis[adjNodes] = 1
# Add the node to queue
q.append(adjNodes)
# Function for DFS traversal
def dfs(self, node, adjLs, vis):
# Mark the node as visited
vis[node] = 1
# Traverse its unvisited neighbours
for it in adjLs[node]:
if not vis[it]:
# Recursively perform DFS
self.dfs(it, adjLs, vis)
# Function to find the number of
# provinces in the given graph
def numProvinces(self, adj):
# Variable to store number of nodes
V = len(adj)
# To store adjacency list
adjLs = [[] for _ in range(V)]
# Convert adjacency matrix to adjacency list
for i in range(V):
for j in range(V):
# self nodes are not considered
if adj[i][j] == 1 and i != j:
adjLs[i].append(j)
adjLs[j].append(i)
# Visited array
vis = [0] * V
# Variable to store number of provinces
cnt = 0
# Start Traversal
for i in range(V):
# If the node is not visited
if not vis[i]:
# Increment counter
cnt += 1
# Start traversal from current node
self.bfs(i, adjLs, vis)
#self.dfs(i, adjLs, vis)
# Return the count
return cnt
# Main function to test the solution
if __name__ == "__main__":
adj = [
[1, 0, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 0],
[1, 0, 0, 1]
]
# Creating an instance of Solution class
sol = Solution()
# Function call to find the provinces in the given graph
ans = sol.numProvinces(adj)
print("The number of provinces in the given graph is:", ans)
class Solution {
// Function for BFS traversal
bfs(node, adjLs, vis) {
// Mark the node as visited
vis[node] = 1;
// Queue required for BFS traversal
let q = [];
// To start traversal from node
q.push(node);
// Keep on traversing till
// the queue is not empty
while (q.length !== 0) {
// Get the node
let i = q.shift();
// Traverse its unvisited neighbours
for (let adjNodes of adjLs[i]) {
if (vis[adjNodes] !== 1) {
// Mark the node as visited
vis[adjNodes] = 1;
// Add the node to queue
q.push(adjNodes);
}
}
}
}
// Function for DFS traversal
dfs(node, adjLs, vis) {
// Mark the node as visited
vis[node] = 1;
// Traverse its unvisited neighbours
for (let it of adjLs[node]) {
if (!vis[it]) {
// Recursively perform DFS
this.dfs(it, adjLs, vis);
}
}
}
// Function to find the number of
// provinces in the given graph
numProvinces(adj) {
// Variable to store number of nodes
let V = adj.length;
// To store adjacency list
let adjLs = new Array(V).fill().map(() => []);
// Convert adjacency matrix to adjacency list
for (let i = 0; i < V; i++) {
for (let j = 0; j < V; j++) {
// self nodes are not considered
if (adj[i][j] === 1 && i !== j) {
adjLs[i].push(j);
adjLs[j].push(i);
}
}
}
// Visited array
let vis = new Array(V).fill(0);
// Variable to store number of provinces
let cnt = 0;
// Start Traversal
for (let i = 0; i < V; i++) {
// If the node is not visited
if (!vis[i]) {
// Increment counter
cnt++;
// Start traversal from current node
this.bfs(i, adjLs, vis);
//this.dfs(i, adjLs, vis);
}
}
// Return the count
return cnt;
}
}
// Main function to test the solution
let adj = [
[1, 0, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 0],
[1, 0, 0, 1]
];
// Creating an instance of Solution class
let sol = new Solution();
// Function call to find the provinces in the given graph
let ans = sol.numProvinces(adj);
console.log("The number of provinces in the given graph is:", ans);
Time Complexity: O(V + E) (where V denotes the number of nodes, E denotes the number of edges)
Space Complexity: O(V + E)
Q: Can we use adjacency lists instead of an adjacency matrix?
A: Yes, but the problem gives a matrix, so directly working with it avoids extra preprocessing. Adjacency lists are better when adj is sparse.
Q: How does Union-Find (Disjoint Set Union) help?
A: Union-Find quickly merges groups, reducing time complexity to nearly O(n) per operation with path compression.
Q: How would you modify this for a directed graph?
A: For directed graphs, strongly connected components (SCCs) should be found using Kosaraju’s or Tarjan’s Algorithm.
Q: How does this change if the matrix is sparse?
A: Convert it into an adjacency list and use optimized BFS/DFS traversal.