Min Edge Movements to Connect a Graph

Last Updated : 22 Jul, 2026

Given a graph with n vertices (0 to n-1) and m edges. You can remove one edge from anywhere and add that edge between any two vertices in one operation.

Find the minimum number of operations that will be required to connect the graph. If it is not possible to connect the graph, return -1.

Examples: 

Input: n = 4, edges[][] = [[0, 1], [0, 2], [1, 2]]
Output: 1
Explanation: Remove edge between vertices 1 and 2 and add between vertices 1 and 3.

Input: n = 6, edges[][] = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3]]
Output: 2
Explanation: Remove edge between (1, 2) and(0, 3) and add edge between (1, 4) and (3, 5)

Try It Yourself
redirect icon

Count Components using DFS - O(n + m) Time and O(n + m) Space

To connect all n vertices, at least n - 1 edges are required. Therefore, if the graph has fewer than n - 1 edges, it is impossible to connect all vertices. Otherwise, we count the number of connected components in the graph using DFS. If there are c connected components, then we need exactly c - 1 operations to connect them, because each operation can connect two components and reduce the number of components by one.

Lets discuss with an example:

remove_edges_to_connected

Since the graph has at least n - 1 = 6 - 1 = 5 edges, there are enough edges to connect all disconnected components. Thus, the problem reduces to counting the number of connected components. If there are 3 components, the minimum number of operations required is 3 - 1 = 2.

Steps:

  • If m < n - 1, return -1.
  • Build the adjacency list of the graph.
  • Use DFS to find the number of connected components.
  • If the number of components is c, return c - 1.
C++
#include <iostream>
#include<vector>
using namespace std;

// DFS to visit all vertices in the current component
void dfs(int node, vector<vector<int>>& adj, vector<bool>& vis) {
    vis[node] = true;

    for (int nei : adj[node]) {
        if (!vis[nei]) {
            dfs(nei, adj, vis);
        }
    }
}

int minEdgesReq(int n, vector<vector<int>>& edges) {

    // A connected graph with n vertices requires
    // at least (n - 1) edges
    if ((int)edges.size() < n - 1) {
        return -1;
    }

    // Build adjacency list
    vector<vector<int>> adj(n);

    for (auto& edge : edges) {
        int u = edge[0];
        int v = edge[1];

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    vector<bool> vis(n, false);
    int components = 0;

    // Count connected components using DFS.
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            components++;
            dfs(i, adj, vis);
        }
    }

    // To connect 'components' disconnected parts,
    // we need exactly (components - 1) operations
    return components - 1;
}


int main() {

    int n = 4;

    vector<vector<int>> edges = {
        {0, 1},
        {0, 2},
        {1, 2}
    };

    cout << minEdgesReq(n, edges) << "\n";

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

public class GFG {
    // DFS to visit all vertices in the current component
    private static void dfs(int node, List<List<Integer>> adj, boolean[] vis) {
        vis[node] = true;

        for (int nei : adj.get(node)) {
            if (!vis[nei]) {
                dfs(nei, adj, vis);
            }
        }
    }

    public static int minEdgesReq(int n, int[][] edges) {
        // A connected graph with n vertices requires
        // at least (n - 1) edges
        if (edges.length < n - 1) {
            return -1;
        }

        // Build adjacency list.
        List<List<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            adj.add(new ArrayList<>());n        }

        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];

            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        boolean[] vis = new boolean[n];
        int components = 0;

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

        // To connect 'components' disconnected parts,
        // we need exactly (components - 1) operations
        return components - 1;
    }

    public static void main(String[] args) {
        int n = 4;

        int[][] edges = {
            {0, 1},
            {0, 2},
            {1, 2}
        };

        System.out.println(minEdgesReq(n, edges));
    }
}
Python
def dfs(node, adj, vis):
    # DFS to visit all vertices in the current component
    vis[node] = True

    for nei in adj[node]:
        if not vis[nei]:
            dfs(nei, adj, vis)


def minEdgesReq(n, edges):

    # A connected graph with n vertices requires
    # at least (n - 1) edges
    if len(edges) < n - 1:
        return -1

    # Build adjacency list
    adj = [[] for _ in range(n)]

    for edge in edges:
        u = edge[0]
        v = edge[1]

        adj[u].append(v)
        adj[v].append(u)

    vis = [False] * n
    components = 0

    # Count connected components using DFS
    for i in range(n):
        if not vis[i]:
            components += 1
            dfs(i, adj, vis)

    # To connect 'components' disconnected parts,
    # we need exactly (components - 1) operations
    return components - 1


if __name__ == "__main__":

    n = 4

    edges = [
        [0, 1],
        [0, 2],
        [1, 2]
    ]

    print(minEdgesReq(n, edges))
C#
using System;
using System.Collections.Generic;

public class GFG
{
    // DFS to visit all vertices in the current component
    private static void Dfs(int node, List<List<int>> adj, bool[] vis)
    {
        vis[node] = true;

        foreach (int nei in adj[node])
        {
            if (!vis[nei])
            {
                Dfs(nei, adj, vis);
            }
        }
    }

    public static int minEdgesReq(int n, int[][] edges)
    {
        // A connected graph with n vertices requires
        // at least (n - 1) edges
        if (edges.Length < n - 1)
        {
            return -1;
        }

        // Build adjacency list
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < n; i++)
        {
            adj.Add(new List<int>());
        }

        foreach (int[] edge in edges)
        {
            int u = edge[0];
            int v = edge[1];

            adj[u].Add(v);
            adj[v].Add(u);
        }

        bool[] vis = new bool[n];
        int components = 0;

        // Count connected components using DFS
        for (int i = 0; i < n; i++)
        {
            if (!vis[i])
            {
                components++;
                Dfs(i, adj, vis);
            }
        }

        // To connect 'components' disconnected parts,
        // we need exactly (components - 1) operations
        return components - 1;
    }

    public static void Main()
    {
        int n = 4;

        int[][] edges = {
            new int[] { 0, 1 },
            new int[] { 0, 2 },
            new int[] { 1, 2 }
        };

        Console.WriteLine(minEdgesReq(n, edges));
    }
}
JavaScript
function dfs(node, adj, vis) {
    // DFS to visit all vertices in the current component
    vis[node] = true;

    for (let nei of adj[node]) {
        if (!vis[nei]) {
            dfs(nei, adj, vis);
        }
    }
}

function minEdgesReq(n, edges) {

    // A connected graph with n vertices requires
    // at least (n - 1) edges
    if (edges.length < n - 1) {
        return -1;
    }

    // Build adjacency list
    let adj = Array.from({length: n}, () => []);

    for (let edge of edges) {
        let u = edge[0];
        let v = edge[1];

        adj[u].push(v);
        adj[v].push(u);
    }

    let vis = Array(n).fill(false);
    let components = 0;

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

    // To connect 'components' disconnected parts,
    // we need exactly (components - 1) operations
    return components - 1;
}

// Driver code
let n = 4;

let edges = [
    [0, 1],
    [0, 2],
    [1, 2]
];

console.log(minEdgesReq(n, edges));

Output
1

Count Components using DSU - O(n + m) Time and O(n) Space

Similar to the DFS approach, a graph needs at least n - 1 edges to become connected. If there are enough edges, we can use Disjoint Set Union (DSU) to efficiently determine how many connected components exist.

Initially, every vertex forms its own component. For each edge, we merge the components of its endpoints. After processing all edges, if there are c connected components, then c - 1 operations are required to connect the entire graph.

Steps:

  • If m < n - 1, return -1.
  • Initialize DSU with each vertex as its own parent.
  • Process every edge and union the sets containing its endpoints.
  • Count the number of distinct components.
  • If the number of components is c, return c - 1.
C++
#include <iostream>
#include<vector>
using namespace std;

// Find the representative (root) of a set
// Path compression flattens the tree, making future finds faster
int find(int x, vector<int>& parent) {
    if (parent[x] != x) {
        parent[x] = find(parent[x], parent);
    }
    return parent[x];
}

int minEdgesReq(int n, vector<vector<int>>& edges) {

    // At least (n - 1) edges are needed to connect n nodes
    if ((int)edges.size() < n - 1) {
        return -1;
    }

    // Initially every node is its own parent
    vector<int> parent(n);
    for (int i = 0; i < n; i++)
        parent[i] = i;

    // Size of each component
    vector<int> size(n, 1);

    for (auto& e : edges) {
        int ru = find(e[0], parent);
        int rv = find(e[1], parent);

        // Already in the same component
        if (ru == rv)
            continue;

        // Attach the smaller component to the larger one
        if (size[ru] < size[rv])
            swap(ru, rv);
        parent[rv] = ru;
        size[ru] += size[rv];
    }

    int components = 0;
    // Count the number of connected components
    for (int i = 0; i < n; i++) {
        if (find(i, parent) == i)
            components++;
    }

    // Need (components - 1) edges to connect all components
    return components - 1;
}


int main() {

    int n = 4;

    vector<vector<int>> edges = {
        {0, 1},
        {0, 2},
        {1, 2}
    };

    cout << minEdgesReq(n, edges) << "\n";

    return 0;
}
Java
import java.util.Arrays;

public class GFG {
    // Find the representative (root) of a set
    // Path compression flattens the tree, making future finds faster
    public static int find(int x, int[] parent) {
        if (parent[x]!= x) {
            parent[x] = find(parent[x], parent);
        }
        return parent[x];
    }

    public static int minEdgesReq(int n, int[][] edges) {
        // At least (n - 1) edges are needed to connect n nodes
        if (edges.length < n - 1) {
            return -1;
        }

        // Initially every node is its own parent
        int[] parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }

        // Size of each component
        int[] size = new int[n];
        Arrays.fill(size, 1);

        for (int[] e : edges) {
            int ru = find(e[0], parent);
            int rv = find(e[1], parent);

            // Already in the same component
            if (ru == rv)
                continue;

            // Attach the smaller component to the larger one
            if (size[ru] < size[rv])
                swap(size, ru, rv);
            parent[rv] = ru;
            size[ru] += size[rv];
        }

        int components = 0;
        // Count the number of connected components
        for (int i = 0; i < n; i++) {
            if (find(i, parent) == i)
                components++;
        }

        // Need (components - 1) edges to connect all components
        return components - 1;
    }

    private static void swap(int[] size, int a, int b) {
        int temp = size[a];
        size[a] = size[b];
        size[b] = temp;
    }

    public static void main(String[] args) {
        int n = 4;

        int[][] edges = {
            {0, 1},
            {0, 2},
            {1, 2}
        };

        System.out.println(minEdgesReq(n, edges));
    }
}
Python
def find(x, parent):
    # Find the representative (root) of a set
    # Path compression flattens the tree, making future finds faster
    if parent[x]!= x:
        parent[x] = find(parent[x], parent)
    return parent[x]


def minEdgesReq(n, edges):
    # At least (n - 1) edges are needed to connect n nodes
    if len(edges) < n - 1:
        return -1

    # Initially every node is its own parent
    parent = [i for i in range(n)]

    # Size of each component
    size = [1] * n

    for e in edges:
        ru = find(e[0], parent)
        rv = find(e[1], parent)

        # Already in the same component
        if ru == rv:
            continue

        # Attach the smaller component to the larger one
        if size[ru] < size[rv]:
            ru, rv = rv, ru
        parent[rv] = ru
        size[ru] += size[rv]

    components = 0
    # Count the number of connected components
    for i in range(n):
        if find(i, parent) == i:
            components += 1

    # Need (components - 1) edges to connect all components
    return components - 1

if __name__ == "__main__":
    n = 4
    
    edges = [
        [0, 1],
        [0, 2],
        [1, 2]
    ]
    
    print(minEdgesReq(n, edges))
C#
using System;

public class GFG {
    // Find the representative (root) of a set
    // Path compression flattens the tree, making future finds faster
    public static int Find(int x, int[] parent) {
        if (parent[x]!= x) {
            parent[x] = Find(parent[x], parent);
        }
        return parent[x];
    }

    public static int minEdgesReq(int n, int[,] edges) {
        // At least (n - 1) edges are needed to connect n nodes
        if (edges.GetLength(0) < n - 1) {
            return -1;
        }

        // Initially every node is its own parent
        int[] parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }

        // Size of each component
        int[] size = new int[n];
        for (int i = 0; i < n; i++) {
            size[i] = 1;
        }

        for (int i = 0; i < edges.GetLength(0); i++) {
            int ru = Find(edges[i, 0], parent);
            int rv = Find(edges[i, 1], parent);

            // Already in the same component
            if (ru == rv)
                continue;

            // Attach the smaller component to the larger one
            if (size[ru] < size[rv])
                Swap(size, ref ru, ref rv);
            parent[rv] = ru;
            size[ru] += size[rv];
        }

        int components = 0;
        // Count the number of connected components
        for (int i = 0; i < n; i++) {
            if (Find(i, parent) == i)
                components++;
        }

        // Need (components - 1) edges to connect all components
        return components - 1;
    }

    private static void Swap(int[] size, ref int a, ref int b) {
        int temp = size[a];
        size[a] = size[b];
        size[b] = temp;
    }

    public static void Main() {
        int n = 4;

        int[,] edges = {
            {0, 1},
            {0, 2},
            {1, 2}
        };

        Console.WriteLine(minEdgesReq(n, edges));
    }
}
JavaScript
function find(x, parent) {
    // Find the representative (root) of a set
    // Path compression flattens the tree, making future finds faster
    if (parent[x]!== x) {
        parent[x] = find(parent[x], parent);
    }
    return parent[x];
}

function minEdgesReq(n, edges) {
    // At least (n - 1) edges are needed to connect n nodes
    if (edges.length < n - 1) {
        return -1;
    }

    // Initially every node is its own parent
    let parent = Array.from({length: n}, (_, i) => i);

    // Size of each component
    let size = Array(n).fill(1);

    for (let e of edges) {
        let ru = find(e[0], parent);
        let rv = find(e[1], parent);

        // Already in the same component
        if (ru === rv)
            continue;

        // Attach the smaller component to the larger one
        if (size[ru] < size[rv])
            [ru, rv] = [rv, ru];
        parent[rv] = ru;
        size[ru] += size[rv];
    }

    let components = 0;
    // Count the number of connected components
    for (let i = 0; i < n; i++) {
        if (find(i, parent) === i)
            components++;
    }

    // Need (components - 1) edges to connect all components
    return components - 1;
}

// Driver code
let n = 4;

let edges = [
    [0, 1],
    [0, 2],
    [1, 2]
];

console.log(minEdgesReq(n, edges));

Output
1
Comment