Bridges in a graph

Last Updated : 23 Oct, 2026

Given an undirected graph represented by an adjacency list adj[][], where adj[i] contains all the nodes adjacent to vertex i, we need to find all the bridges present in the graph.

  • An edge in an undirected connected graph is called a Bridge if removing it increases the number of connected components (i.e., disconnects the graph).
  • For a disconnected undirected graph, a bridge is still an edge whose removal increases the number of disconnected components.

Examples:

Input:  adj[][]= [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3]]

Bridge1

Output: [[0, 3], [3, 4]]
Explanation: If we disconnect the edges (0, 3) or (3, 4), the graph gets divided into multiple disconnected components. Hence, these edges are bridges.

Input: adj[][] =[[1], [2], [3], []]

Bridge3

Output: [[0, 1], [1, 2], [2, 3]]
Explanation: If we disconnect the edges (0, 1) or (1, 2) or (3, 4), the graph gets divided into multiple disconnected components. Hence, these edges are bridges.

Try It Yourself
redirect icon

[Naive Approach] Remove Edges One by One - O(e*(v+e)) Time and O(v+e) Space

The idea is to check if an edge is a bridge by temporarily removing it and testing connectivity.

We perform a DFS excluding the current edge and observe if all vertices remain reachable or not. If any vertex becomes unreachable, then that edge is a bridge, as its removal increases components.

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


// DFS utility to check connectivity after removing an edge
void dfs(int u, vector<vector<int>>& adj, vector<bool>& visited,
         int skipU, int skipV) {
    visited[u] = true;

    for (int v : adj[u]) {
        
        // Skip the edge we are testing
        if ((u == skipU && v == skipV) ||
            (u == skipV && v == skipU)) {
            continue;
        }

        if (!visited[v]) {
            dfs(v, adj, visited, skipU, skipV);
        }
    }
}

// Check if removing edge (u, v) disconnects its endpoints
bool isBridge(int u, int v, vector<vector<int>>& adj, int vCount) {
    vector<bool> visited(vCount, false);

    // Start DFS from one endpoint of the edge
    dfs(u, adj, visited, u, v);

    // If the other endpoint is unreachable, the edge is a bridge
    return !visited[v];
}

// Function to find all bridges
vector<vector<int>> findBridges(vector<vector<int>>& adj) {
    vector<vector<int>> bridges;
    int v = adj.size();

    // Check each edge
    for (int u = 0; u < v; u++) {
        for (int w : adj[u]) {
            
            // Avoid duplicate checking
            if (u < w) {
                if (isBridge(u, w, adj, v)) {
                    bridges.push_back({u, w});
                }
            }
        }
    }

    return bridges;
}

int main() {

    vector<vector<int>> adj = {{1, 2, 3},{0, 2},{0, 1}, {0, 4},{3}};


//Driver Code Starts
    vector<vector<int>> res = findBridges(adj);

    for (auto bridge : res) {
        cout << "[" << bridge[0] << ", " << bridge[1] << "] ";
    }

    return 0;
}

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

class GFG {
//Driver Code Ends


    // DFS utility to check connectivity after removing an edge
    static void dfs(int u, ArrayList<ArrayList<Integer>> adj, boolean[] visited,
                    int skipU, int skipV) {
        visited[u] = true;

        for (int v : adj.get(u)) {

            // Skip the edge we are testing
            if ((u == skipU && v == skipV) || (u == skipV && v == skipU)) {
                continue;
            }

            if (!visited[v]) {
                dfs(v, adj, visited, skipU, skipV);
            }
        }
    }

    // Check if removing edge (u, v) disconnects the graph
    static boolean isBridge(int u, int v, ArrayList<ArrayList<Integer>> adj, int vCount) {
        boolean[] visited = new boolean[vCount];

        // Start DFS from one endpoint of the edge
        dfs(u, adj, visited, u, v);

        return !visited[v];
    }

    // Function to find all bridges
    static ArrayList<ArrayList<Integer>> findBridges(ArrayList<ArrayList<Integer>> adj) {

        ArrayList<ArrayList<Integer>> bridges = new ArrayList<>();
        int v = adj.size();

        // Check each edge (u, w)
        for (int u = 0; u < v; u++) {
            for (int w : adj.get(u)) {

                // To avoid duplicate checking
                if (u < w) {
                    if (isBridge(u, w, adj, v)) {
                        ArrayList<Integer> bridge = new ArrayList<>();
                        bridge.add(u);
                        bridge.add(w);
                        bridges.add(bridge);
                    }
                }
            }
        }

        return bridges;
    }

    // Helper function to add an edge
    static void addEdge(ArrayList<ArrayList<Integer>> adj, int u, int v) {

//Driver Code Starts
        adj.get(u).add(v);
        adj.get(v).add(u);
    }

    public static void main(String[] args) {

        int v = 5;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();

        for (int i = 0; i < v; i++) {
            adj.add(new ArrayList<>());
        }

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 0, 3);
        addEdge(adj, 1, 2);
        addEdge(adj, 3, 4);

        ArrayList<ArrayList<Integer>> res = findBridges(adj);

        for (ArrayList<Integer> bridge : res) {
            System.out.print(bridge + " ");
        }
    }
}
//Driver Code Ends
Python
# DFS utility to check connectivity after removing an edge
def dfs(u, adj, visited, skipU, skipV):
    visited[u] = True

    for v in adj[u]:
        
        # Skip the edge we are testing
        if (u == skipU and v == skipV) or (u == skipV and v == skipU):
            continue
        if not visited[v]:
            dfs(v, adj, visited, skipU, skipV)


# Check if removing edge (u, v) disconnects the graph
def isBridge(u, v, adj, vCount):
    visited = [False] * vCount

    # Start DFS from a different node
    start = 0 if u != 0 else 1

    dfs(start, adj, visited, u, v)

    for i in range(vCount):
        if not visited[i]:
            return True
    return False


# Function to find all bridges 
def findBridges(adj):

    bridges = []
    v = len(adj)

    # Check each edge (u, v)
    for u in range(v):
        for w in adj[u]:
            
            # To avoid duplicate checking
            if u < w:
                if isBridge(u, w, adj, v):
                    bridges.append([u, w])

    return bridges


#Driver Code Starts

if __name__ == "__main__":

    # Given adjacency list
    adj = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3]]

    res = findBridges(adj)

    for bridge in res:
        print(f"[{bridge[0]}, {bridge[1]}]", end=" ")

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

class GFG
{
//Driver Code Ends

    // DFS utility to check connectivity after removing an edge
    static void dfs(int u, List<List<int>> adj, bool[] visited, int skipU, int skipV)
    {
        visited[u] = true;

        foreach (int v in adj[u])
        {
            // Skip the edge we are testing
            if ((u == skipU && v == skipV) || (u == skipV && v == skipU))
                continue;

            if (!visited[v])
                dfs(v, adj, visited, skipU, skipV);
        }
    }

    // Check if removing edge (u, v) disconnects its endpoints
    static bool isBridge(int u, int v, List<List<int>> adj, int vCount)
    {
        bool[] visited = new bool[vCount];

        // Start DFS from one endpoint of the edge
        dfs(u, adj, visited, u, v);

        // If the other endpoint is unreachable, the edge is a bridge
        return !visited[v];
    }

    // Function to find all bridges
    static List<List<int>> findBridges(List<List<int>> adj)
    {
        List<List<int>> bridges = new List<List<int>>();
        int v = adj.Count;

        // Check each edge
        for (int u = 0; u < v; u++)
        {
            foreach (int w in adj[u])
            {
                // Avoid duplicate checking
                if (u < w)
                {
                    if (isBridge(u, w, adj, v))
                    {
                        bridges.Add(new List<int> { u, w });
                    }
                }
            }
        }

        return bridges;
    }

    // Helper function to add an edge
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);

//Driver Code Starts
    }

    static void Main()
    {
        int v = 5;
        List<List<int>> adj = new List<List<int>>();

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

        // Add edges
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 2);
        addEdge(adj, 0, 3);
        addEdge(adj, 1, 2);
        addEdge(adj, 3, 4);

        List<List<int>> res = findBridges(adj);

        foreach (var bridge in res)
        {
            Console.Write($"[{bridge[0]}, {bridge[1]}] ");
        }
    }
}
//Driver Code Ends
JavaScript
// DFS utility to check connectivity after removing an edge
function dfs(u, adj, visited, skipU, skipV) {
    visited[u] = true;

    for (let v of adj[u]) {
        // Skip the edge we are testing
        if ((u === skipU && v === skipV) ||
            (u === skipV && v === skipU)) {
            continue;
        }

        if (!visited[v]) {
            dfs(v, adj, visited, skipU, skipV);
        }
    }
}

// Check if removing edge (u, v) disconnects the graph
function isBridge(u, v, adj, vCount) {
    const visited = new Array(vCount).fill(false);

    // Start DFS from one endpoint of the edge
    dfs(u, adj, visited, u, v);

    // If the other endpoint is unreachable, the edge is a bridge
    return !visited[v];
}

// Function to find all bridges
function findBridges(adj) {
    const bridges = [];
    const v = adj.length;

    // Check each edge
    for (let u = 0; u < v; u++) {
        for (let w of adj[u]) {
            // Avoid duplicate checking
            if (u < w) {
                if (isBridge(u, w, adj, v)) {
                    bridges.push([u, w]);
                }
            }
        }
    }

    return bridges;
}

// Driver code
const adj = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3]];

const res = findBridges(adj);

for (const bridge of res) {
    process.stdout.write(`[${bridge[0]}, ${bridge[1]}] `);

}

Output
[0, 3] [3, 4] 

Time Complexity: O(E * (V + E)), due to DFS for each edge in edgeList where E and V denote number of edges and vertices respectively.
Space Complexity: O(V + E), due to space used for adjacency list and visited array

[Expected Approach] Tarjan's Algorithm - O(V+E) Time and O(V) Space

The goal is to detect bridges in one single DFS traversal - without repeatedly removing edges. If a node v cannot reach any ancestor of its parent node u in the DFS tree, then the edge (u, v) is a bridge. Tarjan's algorithm uses two additional timestamps to implement this along with visited[] that we use in normal DFS.

  • disc[u] -> The discovery time of node u during DFS (the time when we first visit it).
  • low[u] -> The earliest discovery time reachable from u, either through its descendants or via back edges.

We perform a Depth-First Search (DFS) with tracking of parent nodes. This helps us differentiate between a tree edge (edge to a child in DFS) and a back edge (edge to an already visited ancestor).

For every adjacent node v of a node u, we handle three cases:

  • If v is the parent of u: We skip this edge.
    It represents the connection we just came from and isn’t needed in further processing.
  • If v is already visited: This indicates a back edge from u to an ancestor v.
    Update low[u] = min(low[u], disc[v]). This captures the earliest discovery time reachable from u via a back edge.
  • If v is not visited: Recurse with DFS on v to explore further.
    After returning, update low[u] = min(low[u], low[v]). This reflects the earliest node reachable from v's subtree.
    Now check if low[v] > disc[u]. This means the subtree rooted at v cannot reach any ancestor of u, making (u, v) a bridge.
C++
//Driver Code Starts
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//Driver Code Ends


void dfs(int u, int parent, vector<vector<int>>& adj, vector<bool>& visited,
         vector<int>& disc, vector<int>& low, int& timer,
         vector<vector<int>>& bridges) {
    
    visited[u] = true;

    // Initialize discovery and low time
    disc[u] = low[u] = timer++;
    
    // Explore all adjacent nodes
    for (int v : adj[u]) {

        // Skip the edge to parent node
        if (v == parent)
            continue;

        // If v is not visited, recurse for it
        if (!visited[v]) {

            dfs(v, u, adj, visited, disc, low, timer, bridges);

            // Update low value of u
            low[u] = min(low[u], low[v]);

            // If low[v] > disc[u], edge (u, v) is a bridge
            if (low[v] > disc[u]) {
                bridges.push_back({u, v});
            }
        }
        else {
            
            // Update low[u] for back edge
            low[u] = min(low[u], disc[v]);
        }
    }
}

// Function to find all bridges (critical connections)
vector<vector<int>> findBridges(vector<vector<int>>& adj) {

    int vCount = adj.size();

    vector<bool> visited(vCount, false);
    
    // Discovery time of nodes
    vector<int> disc(vCount, -1);  
    
     // Lowest reachable discovery time
    vector<int> low(vCount, -1);  
    vector<vector<int>> bridges;
    int timer = 0;

    // Run DFS for each unvisited node
    for (int i = 0; i < vCount; i++) {
        if (!visited[i]) {
            dfs(i, -1, adj, visited, disc, low, timer, bridges);
        }
    }

    return bridges;
}


//Driver Code Starts
int main() {

    // Given adjacency list
    vector<vector<int>> adj = {{1, 2, 3},{0, 2},{0, 1},{0, 4},{3}};

    vector<vector<int>> res = findBridges(adj);

    for (auto bridge : res) {
        cout << "[" << bridge[0] << ", " << bridge[1] << "] ";
    }

    return 0;
}

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

public class GFG {
//Driver Code Ends


    static void dfs(int u, int parent, ArrayList<ArrayList<Integer>> adj, boolean[] visited,
                    int[] disc, int[] low, int[] timer, ArrayList<ArrayList<Integer>> bridges) {

        visited[u] = true;

        // Initialize discovery and low time
        disc[u] = low[u] = timer[0]++;
        
        // Explore all adjacent nodes
        for (int v : adj.get(u)) {

            // Skip the edge to parent node
            if (v == parent)
                continue;

            // If v is not visited, recurse for it
            if (!visited[v]) {

                dfs(v, u, adj, visited, disc, low, timer, bridges);

                // Update low value of u
                low[u] = Math.min(low[u], low[v]);

                // If low[v] > disc[u], edge (u, v) is a bridge
                if (low[v] > disc[u]) {
                    ArrayList<Integer> bridge = new ArrayList<>();
                    bridge.add(u);
                    bridge.add(v);
                    bridges.add(bridge);
                }
            } else {
                // Update low[u] for back edge
                low[u] = Math.min(low[u], disc[v]);
            }
        }
    }

    // Function to find all bridges (critical connections)
    static ArrayList<ArrayList<Integer>> findBridges(ArrayList<ArrayList<Integer>> adj) {

        int vCount = adj.size();

        boolean[] visited = new boolean[vCount];
        
        // Discovery time of nodes
        int[] disc = new int[vCount];
        
        // Lowest reachable discovery time
        int[] low = new int[vCount];
        Arrays.fill(disc, -1);
        Arrays.fill(low, -1);
        
        ArrayList<ArrayList<Integer>> bridges = new ArrayList<>();
        int[] timer = {0};

        // Run DFS for each unvisited node
        for (int i = 0; i < vCount; i++) {
            if (!visited[i]) {
                dfs(i, -1, adj, visited, disc, low, timer, bridges);
            }
        }

        return bridges;
    }
    
    

//Driver Code Starts
    // Function to add an undirected edge
    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 = 5;
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();

        for (int i = 0; i < v; i++) {
            adj.add(new ArrayList<>());
        }

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

        ArrayList<ArrayList<Integer>> res = findBridges(adj);

        for (ArrayList<Integer> bridge : res) {
            System.out.print("[" + bridge.get(0) + ", " + bridge.get(1) + "] ");
        }
    }
}

//Driver Code Ends
Python
def dfs(u, parent, adj, visited, disc, low, timer, bridges):
    
    visited[u] = True

    # Initialize discovery and low time
    disc[u] = low[u] = timer[0]
    timer[0] += 1
    
    # Explore all adjacent nodes
    for v in adj[u]:

        # Skip the edge to parent node
        if v == parent:
            continue

        # If v is not visited, recurse for it
        if not visited[v]:

            dfs(v, u, adj, visited, disc, low, timer, bridges)

            # Update low value of u
            low[u] = min(low[u], low[v])

            # If low[v] > disc[u], edge (u, v) is a bridge
            if low[v] > disc[u]:
                bridges.append([u, v])
        else:
            
            # Update low[u] for back edge
            low[u] = min(low[u], disc[v])


# Function to find all bridges (critical connections)
def findBridges(adj):

    vCount = len(adj)

    visited = [False] * vCount
    
    # Discovery time of nodes
    disc = [-1] * vCount  
    
    # Lowest reachable discovery time
    low = [-1] * vCount  
    bridges = []
    timer = [0]

    # Run DFS for each unvisited node
    for i in range(vCount):
        if not visited[i]:
            dfs(i, -1, adj, visited, disc, low, timer, bridges)

    return bridges



#Driver Code Starts

if __name__ == "__main__":
    adj = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3]]
    
    res = findBridges(adj)
    
    for bridge in res:
        print(f"[{bridge[0]}, {bridge[1]}]", end=" ")

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

public class GFG
{
//Driver Code Ends

    
    static void dfs(int u, int parent, List<List<int>> adj, List<bool> visited,
                    List<int> disc, List<int> low, ref int timer,
                    List<List<int>> bridges)
    {
        visited[u] = true;

        // Initialize discovery and low time
        disc[u] = low[u] = timer++;

        // Explore all adjacent nodes
        foreach (int v in adj[u])
        {
            // Skip the edge to parent node
            if (v == parent)
                continue;

            // If v is not visited, recurse for it
            if (!visited[v])
            {
                dfs(v, u, adj, visited, disc, low, ref timer, bridges);

                // Update low value of u
                low[u] = Math.Min(low[u], low[v]);

                // If low[v] > disc[u], edge (u, v) is a bridge
                if (low[v] > disc[u])
                {
                    bridges.Add(new List<int> { u, v });
                }
            }
            else
            {
                // Update low[u] for back edge
                low[u] = Math.Min(low[u], disc[v]);
            }
        }
    }

//Driver Code Starts
    

    // Function to add an undirected edge
    static void addEdge(List<List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }

    // Function to find all bridges (critical connections)
    static List<List<int>> findBridges(List<List<int>> adj)
    {
        int vCount = adj.Count;

        List<bool> visited = new List<bool>(new bool[vCount]);

        // Discovery time of nodes
        List<int> disc = new List<int>(new int[vCount]);

        // Lowest reachable discovery time
        List<int> low = new List<int>(new int[vCount]);

        for (int i = 0; i < vCount; i++)
        {
            disc[i] = -1;
            low[i] = -1;
        }

        List<List<int>> bridges = new List<List<int>>();
        int timer = 0;

        // Run DFS for each unvisited node
        for (int i = 0; i < vCount; i++)
        {
            if (!visited[i])
            {
                dfs(i, -1, adj, visited, disc, low, ref timer, bridges);
            }
        }

        return bridges;
    }

    public static void main()
    {
        int v = 5;
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < v; i++)
        {
            adj.Add(new List<int>());
        }

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

        List<List<int>> res = findBridges(adj);

        foreach (List<int> bridge in res)
        {
            Console.Write($"[{bridge[0]}, {bridge[1]}] ");
        }
    }
}

//Driver Code Ends
JavaScript
function dfs(u, parent, adj, visited, disc, low, timer, bridges) {
    
    visited[u] = true;

    // Initialize discovery and low time
    disc[u] = low[u] = timer.value++;
    
    // Explore all adjacent nodes
    for (let v of adj[u]) {

        // Skip the edge to parent node
        if (v === parent)
            continue;

        // If v is not visited, recurse for it
        if (!visited[v]) {

            dfs(v, u, adj, visited, disc, low, timer, bridges);

            // Update low value of u
            low[u] = Math.min(low[u], low[v]);

            // If low[v] > disc[u], edge (u, v) is a bridge
            if (low[v] > disc[u]) {
                bridges.push([u, v]);
            }
        } else {
            
            // Update low[u] for back edge
            low[u] = Math.min(low[u], disc[v]);
        }
    }
}

// Function to find all bridges (critical connections)
function findBridges(adj) {

    let vCount = adj.length;

    let visited = new Array(vCount).fill(false);
    
    // Discovery time of nodes
    let disc = new Array(vCount).fill(-1);
    
    // Lowest reachable discovery time
    let low = new Array(vCount).fill(-1);
    let bridges = [];
    let timer = { value: 0 };

    // Run DFS for each unvisited node
    for (let i = 0; i < vCount; i++) {
        if (!visited[i]) {
            dfs(i, -1, adj, visited, disc, low, timer, bridges);
        }
    }

    return bridges;
}



//Driver Code Starts
//Driver Code
// Given adjacency list
let adj = [[1, 2, 3], [0, 2], [0, 1], [0, 4], [3]];

let res = findBridges(adj);

for (let bridge of res) {
    process.stdout.write(`[${bridge[0]}, ${bridge[1]}] `);
}

//Driver Code Ends

Output
[3, 4] [0, 3] 
Comment