Minimum Operations to Connect Hospitals

Last Updated : 21 Nov, 2025

In a city, there are many hospitals. Each hospital is connected to some other hospitals, represented using an adjacency list adj[][], where adj[i] contains all hospitals directly connected to the i-th hospital.
Our task is to ensure that all hospitals are connected, either directly or indirectly to each other. In one operation, we can remove an existing link and reconnect it between two previously disconnected hospitals. Determine the minimum number of operations required to make the entire network connected. If it is impossible, return -1.

Examples:

Input: adj[][] = [[1, 2], [0, 2], [0, 1], []]
Output: 1
Explanation: Remove the connection between hospitals 1 and 2 and connect the hospitals 1 and 3.

image1

Input: adj[][]= [[1, 2], [0], [0, 3], [2, 4],[3]]
Output: 0
Explanation: All hospitals are already connected directly or indirectly. No rearrangement of connections is required.

image2
Try It Yourself
redirect icon

Intuition:
To connect all hospitals into one complete network, we must ensure that every hospital is reachable from every other hospital and that the entire system forms a single connected component. To connect all disconnected groups of hospitals, we need extra edges. These extra edges come from redundant connections- links that connect hospitals already reachable through some other path.
If the number of extra edges is enough to connect all disconnected groups, i.e., if extra edges ≥ (disconnected components − 1), then we can rebuild the network. In that case, the minimum number of operations needed will also be (disconnected components − 1) because that’s exactly how many new links are required to make the whole system fully connected.

[Approach 1] Using Disjoint Set

We use a Disjoint Set Union (DSU), because it helps us efficiently identify if two hospitals are already connected (directly or indirectly) and also merge two disconnected hospitals into one connected component whenever an edge exists.

While traversing, if two hospitals already belong to the same component, it means the current connection is redundant or extra. Otherwise, we merge them into one set. By the time we finish processing all connections, we know exactly how many extra edges we have.
Next, to find how many disconnected components exist, we check each hospital and see whether it has a different parent. If a hospital’s parent is different from others, it belongs to a different component.

After that, we simply compare the number of extra edges with the number of disconnected components to determine whether the entire network can be connected.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
using namespace std;
//Driver Code Ends


class DisjointSet {
    vector<int> rank, parent, size;

public:
    DisjointSet(int n) {
        rank.resize(n + 1, 0);
        parent.resize(n + 1);
        size.resize(n + 1);
        for (int i = 0; i <= n; i++) {
            parent[i] = i;
            size[i] = 1;
        }
    }

    // Find the ultimate parent of a node (with path compression)
    int findUPar(int node) {
        if (node == parent[node])
            return node;
        return parent[node] = findUPar(parent[node]);
    }

    // Union by size
    void unionBySize(int u, int v) {
        int ulpU = findUPar(u);
        int ulpV = findUPar(v);
        if (ulpU == ulpV) return;
        if (size[ulpU] < size[ulpV]) {
            parent[ulpU] = ulpV;
            size[ulpV] += size[ulpU];
        } else {
            parent[ulpV] = ulpU;
            size[ulpU] += size[ulpV];
        }
    }
};

// Function to find minimum operations required
int minConnect(vector<vector<int>>& adj) {
    int n = adj.size();
    DisjointSet ds(n);
    int extra = 0;

    // Traverse all links in adjacency list
    for (int u = 0; u < n; u++) {
        for (int v : adj[u]) {
            
            // To avoid processing duplicate edges 
            if (u < v) {
                
                // If both hospitals are already connected,
                //mark this link as extra
                if (ds.findUPar(u) == ds.findUPar(v))
                    extra++;
                else
                    ds.unionBySize(u, v);
            }
        }
    }

    // Count disconnected components
    int components = 0;
    for (int i = 0; i < n; i++) {
       if(ds.findUPar(i)==i){
           components++;
       }
    }

    // If enough extra links exist to connect all components
    if (extra >= components - 1)
        return components - 1;
    else
        return -1;
}

//Driver Code Starts


int main() {
    
   vector<vector<int>> adj = {
        {{1, 2}, {0, 2}, {0, 1}, {}}
    };

    cout << minConnect(adj) << endl;
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.Collections;

//Driver Code Ends

class DisjointSet {
    ArrayList<Integer> rank, parent, size;

    DisjointSet(int n) {
        rank = new ArrayList<>(Collections.nCopies(n + 1, 0));

        parent = new ArrayList<>(n + 1);
        size = new ArrayList<>(n + 1);

        for (int i = 0; i <= n; i++) {
            parent.add(i);
            size.add(1);
        }
    }

    // Find the ultimate parent of a node (with path compression)
    int findUPar(int node) {
        if (node == parent.get(node))
            return node;
        parent.set(node, findUPar(parent.get(node)));
        return parent.get(node);
    }

    // Union by size
    void unionBySize(int u, int v) {
        int ulpU = findUPar(u);
        int ulpV = findUPar(v);
        if (ulpU == ulpV) return;

        if (size.get(ulpU) < size.get(ulpV)) {
            parent.set(ulpU, ulpV);
            size.set(ulpV, size.get(ulpV) + size.get(ulpU));
        } else {
            parent.set(ulpV, ulpU);
            size.set(ulpU, size.get(ulpU) + size.get(ulpV));
        }
    }
}

public class GFG {

    // Function to find minimum operations required
    static int minConnect(ArrayList<ArrayList<Integer>> adj) {
        int n = adj.size();
        DisjointSet ds = new DisjointSet(n);
        int extra = 0;

        // Traverse all links in adjacency list
        for (int u = 0; u < n; u++) {
            for (int v : adj.get(u)) {

                // avoid duplicate edges
                if (u < v) {

                    if (ds.findUPar(u) == ds.findUPar(v))
                        extra++;
                    else
                        ds.unionBySize(u, v);
                }
            }
        }

        // Count disconnected components
        int components = 0;
        for (int i = 0; i < n; i++) {
            if (ds.findUPar(i) == i)
                components++;
        }

        // Check if extra edges are enough
        if (extra >= components - 1)
            return components - 1;
        return -1;
    }


//Driver Code Starts
    // Function to add edges in adjacency list
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }

    public static void main(String[] args) {

        int V = 4;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < V; i++) adj.add(new ArrayList<>());

        // Adding edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);

        System.out.println(minConnect(adj));
    }
}

//Driver Code Ends
Python
class DisjointSet:
    def __init__(self, n):
        self.rank = [0] * (n + 1)
        self.parent = [i for i in range(n + 1)]
        self.size = [1] * (n + 1)

    # Find the ultimate parent of a node (with path compression)
    def findUPar(self, node):
        if node == self.parent[node]:
            return node
        self.parent[node] = self.findUPar(self.parent[node])
        return self.parent[node]

    # Union by size
    def unionBySize(self, u, v):
        ulpU = self.findUPar(u)
        ulpV = self.findUPar(v)
        if ulpU == ulpV:
            return

        if self.size[ulpU] < self.size[ulpV]:
            self.parent[ulpU] = ulpV
            self.size[ulpV] += self.size[ulpU]
        else:
            self.parent[ulpV] = ulpU
            self.size[ulpU] += self.size[ulpV]

# Function to find minimum operations required
def minConnect(adj):
    n = len(adj)
    ds = DisjointSet(n)
    extra = 0

    # Traverse all links in adjacency list
    for u in range(n):
        for v in adj[u]:

            # To avoid processing duplicate edges 
            if u < v:

                # If both hospitals are already connected,
                #mark this link as extra
                if ds.findUPar(u) == ds.findUPar(v):
                    extra += 1
                else:
                    ds.unionBySize(u, v)

    # Count disconnected components using DFS
    components = sum(1 for i in range(n) if ds.findUPar(i) == i)

    # If enough extra links exist to connect all components
    if extra >= components - 1:
        return components - 1
    else:
        return -1


#Driver Code Starts

if __name__ == "__main__":
    
    # Adjacency list
    adj = [[1, 2],[0, 2],[0, 1],[]]

    print(minConnect(adj))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

//Driver Code Ends

class DisjointSet
{
    List<int> rank, parent, size;

    public DisjointSet(int n)
    {
        rank = new List<int>(new int[n + 1]);
        parent = new List<int>(n + 1);
        size = new List<int>(n + 1);

        for (int i = 0; i <= n; i++)
        {
            parent.Add(i);
            size.Add(1);
        }
    }

    // Find the ultimate parent of a node (with path compression)
    public int findUPar(int node)
    {
        if (node == parent[node])
            return node;

        parent[node] = findUPar(parent[node]);
        return parent[node];
    }

    // Union by size
    public void unionBySize(int u, int v)
    {
        int ulpU = findUPar(u);
        int ulpV = findUPar(v);

        if (ulpU == ulpV) return;

        if (size[ulpU] < size[ulpV])
        {
            parent[ulpU] = ulpV;
            size[ulpV] = size[ulpV] + size[ulpU];
        }
        else
        {
            parent[ulpV] = ulpU;
            size[ulpU] = size[ulpU] + size[ulpV];
        }
    }
}

class GFG
{
    // Function to find minimum operations required
    static int minConnect(List<List<int>> adj)
    {
        int n = adj.Count;
        DisjointSet ds = new DisjointSet(n);
        int extra = 0;

        // Traverse all links in adjacency list
        for (int u = 0; u < n; u++)
        {
            foreach (int v in adj[u])
            {
                // avoid duplicate edges
                if (u < v)
                {
                    if (ds.findUPar(u) == ds.findUPar(v))
                        extra++;
                    else
                        ds.unionBySize(u, v);
                }
            }
        }

        // Count disconnected components
        int components = 0;
        for (int i = 0; i < n; i++)
        {
            if (ds.findUPar(i) == i)
                components++;
        }

        // Check if extra edges are enough
        if (extra >= components - 1)
            return components - 1;

        return -1;
    }

//Driver Code Starts

    // Function to add edges in adjacency list
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }

    public static void Main(string[] args)
    {
        int V = 4;
        List<List<int>> adj = new List<List<int>>();

        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Adding edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);

        Console.WriteLine(minConnect(adj));
    }
}

//Driver Code Ends
JavaScript
class DisjointSet {
    constructor(n) {
        this.rank = new Array(n + 1).fill(0);
        this.parent = Array.from({ length: n + 1 }, (_, i) => i);
        this.size = new Array(n + 1).fill(1);
    }

    // Find the ultimate parent of a node (with path compression)
    findUPar(node) {
        if (node === this.parent[node]) return node;
        this.parent[node] = this.findUPar(this.parent[node]);
        return this.parent[node];
    }

    // Union by size
    unionBySize(u, v) {
        let ulpU = this.findUPar(u);
        let ulpV = this.findUPar(v);

        if (ulpU === ulpV) return;

        if (this.size[ulpU] < this.size[ulpV]) {
            this.parent[ulpU] = ulpV;
            this.size[ulpV] += this.size[ulpU];
        } else {
            this.parent[ulpV] = ulpU;
            this.size[ulpU] += this.size[ulpV];
        }
    }
}
// Function to find minimum operations required
function minConnect(adj) {
    const n = adj.length;
    const ds = new DisjointSet(n);
    let extra = 0;

    // Traverse all links in adjacency list
    for (let u = 0; u < n; u++) {
        for (let v of adj[u]) {

            // To avoid processing duplicate edges 
            if (u < v) {

                // If both hospitals are already connected,
                //mark this link as extra
                if (ds.findUPar(u) === ds.findUPar(v))
                    extra++;
                else
                    ds.unionBySize(u, v);
            }
        }
    }

    // Count disconnected components using DFS
    let components = 0;
    for (let i = 0; i < n; i++) {
        if (ds.findUPar(i) === i)
            components++;
    }

    // If enough extra links exist to connect all components
    return extra >= components - 1 ? components - 1 : -1;
}



//Driver Code Starts
//Driver Code

// Adjacency list
const adj = [[1, 2],[0, 2],[0, 1],[]];

console.log(minConnect(adj));

//Driver Code Ends

Output
1

Time Complexity: O(V+E), V = number of hospitals (nodes), E = total number of links (edges)
Auxiliary Space: O (V + E)

[Approach 2] Using DFS

According to the MST property, a component with V vertices requires exactly (V − 1) edges to stay fully connected. If more edges than required are present, those extra edges are redundant and can be reused to connect other disconnected hospitals.
We compute the number of extra edges using:
Extra Edges = Total Edges − (Vertices − Disconnected Components)


After this, we simply find the number of disconnected components using DFS and check whether the extra edges are enough to connect them. To connect all components, we need (Disconnected Components − 1) edges. If the extra edges are at least this number, all hospitals can be connected; otherwise, it is impossible.

C++
//Driver Code Starts
#include <iostream>
#include<vector>
using namespace std;
//Driver Code Ends


// DFS function to visit all hospitals in a connected component
void dfs(int start, vector<vector<int>>& adj, vector<bool>& visited) {
    visited[start] = true;
    for (int neighbor : adj[start]) {
        if (!visited[neighbor])
            dfs(neighbor, adj, visited);
    }
}

int minConnect(vector<vector<int>>& adj) {
    int V = adj.size();
    vector<bool> visited(V, false);
    int edges = 0;

    // Count total number of edges 
    for (int i = 0; i < V; i++)
        edges += adj[i].size();
        
        edges/=2;

    // Count disconnected components using DFS
    int components = 0;
    for (int i = 0; i < V; i++) {
        if (!visited[i]) {
            components++;
            dfs(i, adj, visited);
        }
    }

    // If total edges are less than (V - 1), it's impossible to connect all
    if (edges < V - 1)
        return -1;

    // Calculate redundant (extra) edges
    int extra = edges - (V -components);

    // If enough extra edges exist to connect all components
    if (extra>= (components - 1))
        return components - 1;

    return -1;
}


//Driver Code Starts
int main() {
   vector<vector<int>> adj = {
        {{1, 2}, {0, 2}, {0, 1}, {}}
    };

    cout << minConnect(adj);
    return 0;
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;

public class GFG {
//Driver Code Ends


    // DFS function to visit all hospitals in a connected component
    static void dfs(int start, ArrayList<ArrayList<Integer>> adj, boolean[] visited) {
        visited[start] = true;
        for (int neighbor : adj.get(start)) {
            if (!visited[neighbor])
                dfs(neighbor, adj, visited);
        }
    }
    static int minConnect(ArrayList<ArrayList<Integer>> adj) {
        int V = adj.size();
        boolean[] visited = new boolean[V];
        int edges = 0;

        // Count total number of edges 
        for (int i = 0; i < V; i++)
            edges += adj.get(i).size();
        edges /= 2;

        // Count disconnected components using DFS
        int components = 0;
        for (int i = 0; i < V; i++) {
            if (!visited[i]) {
                components++;
                dfs(i, adj, visited);
            }
        }

        // If total edges are less than (V - 1), it's impossible to connect all
        if (edges < V - 1)
            return -1;

        // Calculate redundant (extra) edges
        int extra = edges - (V -components);

        // If enough extra edges exist to connect all components
        if (extra >= (components - 1))
            return components - 1;

        return -1;
    }
    

//Driver Code Starts
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {
        adj.get(u).add(v);
        adj.get(v).add(u);
    }

    public static void main(String[] args) {
        int n = 4;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < n; i++) adj.add(new ArrayList<>());

        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);

        System.out.println(minConnect(adj));
    }
}

//Driver Code Ends
Python
# DFS function to visit all hospitals in a connected component
def dfs(start, adj, visited):
    visited[start] = True
    for neighbor in adj[start]:
        if not visited[neighbor]:
            dfs(neighbor, adj, visited)

def minConnect(adj):
    V = len(adj)
    visited = [False] * V
    edges = 0

    # Count total number of edges 
    for i in range(V):
        edges += len(adj[i])
    edges //= 2

    # Count disconnected components using DFS
    components = 0
    for i in range(V):
        if not visited[i]:
            components += 1
            dfs(i, adj, visited)

    # If total edges are less than (V - 1), it's impossible to connect all
    if edges < V - 1:
        return -1

    # Calculate redundant (extra) edges
    extra = edges - (V -components);

    # If enough extra edges exist to connect all components
    if extra >= (components - 1):
        return components - 1

    return -1



#Driver Code Starts
if __name__ == "__main__":
    adj = [[1, 2],[0, 2],[0, 1],[]]
    
    print(minConnect(adj))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG
{
//Driver Code Ends

    // DFS function to visit all hospitals in a connected component
    static void dfs(int start, List<List<int>> adj, bool[] visited)
    {
        visited[start] = true;
        foreach (int neighbor in adj[start])
        {
            if (!visited[neighbor])
                dfs(neighbor, adj, visited);
        }
    }

    static int minConnect(List<List<int>> adj)
    {
        int V = adj.Count;
        bool[] visited = new bool[V];
        int edges = 0;

        // Count total number of edges 
        for (int i = 0; i < V; i++)
            edges += adj[i].Count;
        edges /= 2;

        // Count disconnected components using DFS
        int components = 0;
        for (int i = 0; i < V; i++)
        {
            if (!visited[i])
            {
                components++;
                dfs(i, adj, visited);
            }
        }

        // If total edges are less than (V - 1), it's impossible to connect all
        if (edges < V - 1)
            return -1;

        // Calculate redundant (extra) edges
        int extra = edges - (V -components);

        // If enough extra edges exist to connect all components
        if (extra >= (components - 1))
            return components - 1;

        return -1;
    }


//Driver Code Starts
    
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }

    static void Main()
    {
        int n = 4;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < n; i++)
            adj.Add(new List<int>());

        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 1, 2);

        Console.WriteLine(minConnect(adj));
    }
}

//Driver Code Ends
JavaScript
// DFS function to visit all hospitals in a connected component
function dfs(start, adj, visited) {
    visited[start] = true;
    for (let neighbor of adj[start]) {
        if (!visited[neighbor]) dfs(neighbor, adj, visited);
    }
}

function minConnect(adj) {
    const V = adj.length;
    const visited = Array(V).fill(false);
    let edges = 0;

    // Count total number of edges 
    for (let i = 0; i < V; i++) edges += adj[i].length;
    edges = Math.floor(edges / 2);

    // Count disconnected components using DFS
    let components = 0;
    for (let i = 0; i < V; i++) {
        if (!visited[i]) {
            components++;
            dfs(i, adj, visited);
        }
    }

    // If total edges are less than (V - 1), it's impossible to connect all
    if (edges < V - 1) return -1;

    // Calculate redundant (extra) edges
    let extra = edges - (V -components);

    // If enough extra edges exist to connect all components
    if (extra >= (components - 1)) return components - 1;

    return -1;
}



//Driver Code Starts
// Driver Code
const adj = [[1, 2],[0, 2],[0, 1],[]];

console.log(minConnect(adj));

//Driver Code Ends

Output
1

Time Complexity: O(V+E)
Auxiliary Space: O(V+E)

Comment