Given an undirected Graph, The task is to find the Bridges in this Graph.
An edge in an undirected connected graph is a bridge if removing it disconnects the graph. For a disconnected undirected graph, the definition is similar, a bridge is an edge removal that increases the number of disconnected components.
Like Articulation Points, bridges represent vulnerabilities in a connected network and are useful for designing reliable networks.
Examples:
Input:

Output: (0, 3) and (3, 4)
Input:

Output: (1, 6)
Input:

Output: (0, 1), (1, 2), and (2, 3)
Naive Approach: Below is the idea to solve the problem:
One by one remove all edges and see if the removal of an edge causes a disconnected graph.
Follow the below steps to Implement the idea:
- For every edge (u, v), do the following:
- Remove (u, v) from the graph
- See if the graph remains connected (either uses BFS or DFS)
- Add (u, v) back to the graph.
Time Complexity: O(E*(V+E)) for a graph represented by an adjacency list.
Auxiliary Space: O(V+E)
Find Bridges in a graph using Tarjan’s Algorithm.
Before heading towards the approach understand which edge is termed as bridge. Suppose there exists a edge from u -> v, now after removal of this edge if v can’t be reached by any other edges then u -> v edge is bridge. Our approach is based on this intuition, so take time and grasp it.
ALGORITHM: –
To implement this algorithm, we need the following data structures –
- visited[ ] = to keep track of the visited vertices to implement DFS
- disc[ ] = to keep track when for the first time that particular vertex is reached
- low[ ] = to keep track of the lowest possible time by which we can reach that vertex ‘other than parent’ so that if edge from parent is removed can the particular node can be reached other than parent.
We will traverse the graph using DFS traversal but with slight modifications i.e. while traversing we will keep track of the parent node by which the particular node is reached because we will update the low[node] = min(low[all it’s adjacent node except parent]) hence we need to keep track of the parent.
While traversing adjacent nodes let ‘v’ of a particular node let ‘u’ 3 cases arise –
1. v is parent of u then,
2. v is visited then,
- update the low of v i.e. low[u] = min( low[u] , disc[v]) this arises when a node can be visited by more than one node, but low is to keep track of the lowest possible time so we will update it.
3. v is not visited then,
- call the DFS to traverse ahead
- now update the low[u] = min( low[u], low[v] ) as we know v can’t be parent cause we have handled that case first.
- now check if ( low[v] > disc[u] ) i.e. the lowest possible to time to reach ‘v’ is greater than ‘u’ this means we can’t reach ‘v’ without ‘u’ so the edge u -> v is a bridge.
Below is the implementation of the above approach:
C++
#include<bits/stdc++.h>
using namespace std;
class Graph
{
int V;
list< int > *adj;
void bridgeUtil( int u, vector< bool >& visited, vector< int >& disc,
vector< int >& low, int parent);
public :
Graph( int V);
void addEdge( int v, int w);
void bridge();
};
Graph::Graph( int V)
{
this ->V = V;
adj = new list< int >[V];
}
void Graph::addEdge( int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v);
}
void Graph::bridgeUtil( int u, vector< bool >& visited, vector< int >& disc,
vector< int >& low, int parent)
{
static int time = 0;
visited[u] = true ;
disc[u] = low[u] = ++ time ;
list< int >::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
int v = *i;
if (v==parent)
continue ;
if (visited[v]){
low[u] = min(low[u], disc[v]);
}
else {
parent = u;
bridgeUtil(v, visited, disc, low, parent);
low[u] = min(low[u], low[v]);
if (low[v] > disc[u])
cout << u << " " << v << endl;
}
}
}
void Graph::bridge()
{
vector< bool > visited (V, false );
vector< int > disc (V,-1);
vector< int > low (V,-1);
int parent = -1;
for ( int i = 0; i < V; i++)
if (visited[i] == false )
bridgeUtil(i, visited, disc, low, parent);
}
int main()
{
cout << "\nBridges in first graph \n" ;
Graph g1(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.bridge();
cout << "\nBridges in second graph \n" ;
Graph g2(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
g2.bridge();
cout << "\nBridges in third graph \n" ;
Graph g3(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
g3.bridge();
return 0;
}
|
Java
import java.io.*;
import java.util.*;
import java.util.LinkedList;
class Graph
{
private int V;
private LinkedList<Integer> adj[];
int time = 0 ;
static final int NIL = - 1 ;
@SuppressWarnings ( "unchecked" )Graph( int v)
{
V = v;
adj = new LinkedList[v];
for ( int i= 0 ; i<v; ++i)
adj[i] = new LinkedList();
}
void addEdge( int v, int w)
{
adj[v].add(w);
adj[w].add(v);
}
void bridgeUtil( int u, boolean visited[], int disc[],
int low[], int parent[])
{
visited[u] = true ;
disc[u] = low[u] = ++time;
Iterator<Integer> i = adj[u].iterator();
while (i.hasNext())
{
int v = i.next();
if (!visited[v])
{
parent[v] = u;
bridgeUtil(v, visited, disc, low, parent);
low[u] = Math.min(low[u], low[v]);
if (low[v] > disc[u])
System.out.println(u+ " " +v);
}
else if (v != parent[u])
low[u] = Math.min(low[u], disc[v]);
}
}
void bridge()
{
boolean visited[] = new boolean [V];
int disc[] = new int [V];
int low[] = new int [V];
int parent[] = new int [V];
for ( int i = 0 ; i < V; i++)
{
parent[i] = NIL;
visited[i] = false ;
}
for ( int i = 0 ; i < V; i++)
if (visited[i] == false )
bridgeUtil(i, visited, disc, low, parent);
}
public static void main(String args[])
{
System.out.println( "Bridges in first graph " );
Graph g1 = new Graph( 5 );
g1.addEdge( 1 , 0 );
g1.addEdge( 0 , 2 );
g1.addEdge( 2 , 1 );
g1.addEdge( 0 , 3 );
g1.addEdge( 3 , 4 );
g1.bridge();
System.out.println();
System.out.println( "Bridges in Second graph" );
Graph g2 = new Graph( 4 );
g2.addEdge( 0 , 1 );
g2.addEdge( 1 , 2 );
g2.addEdge( 2 , 3 );
g2.bridge();
System.out.println();
System.out.println( "Bridges in Third graph " );
Graph g3 = new Graph( 7 );
g3.addEdge( 0 , 1 );
g3.addEdge( 1 , 2 );
g3.addEdge( 2 , 0 );
g3.addEdge( 1 , 3 );
g3.addEdge( 1 , 4 );
g3.addEdge( 1 , 6 );
g3.addEdge( 3 , 5 );
g3.addEdge( 4 , 5 );
g3.bridge();
}
}
|
Python3
from collections import defaultdict
class Graph:
def __init__( self ,vertices):
self .V = vertices
self .graph = defaultdict( list )
self .Time = 0
def addEdge( self ,u,v):
self .graph[u].append(v)
self .graph[v].append(u)
def bridgeUtil( self ,u, visited, parent, low, disc):
visited[u] = True
disc[u] = self .Time
low[u] = self .Time
self .Time + = 1
for v in self .graph[u]:
if visited[v] = = False :
parent[v] = u
self .bridgeUtil(v, visited, parent, low, disc)
low[u] = min (low[u], low[v])
if low[v] > disc[u]:
print ( "%d %d" % (u,v))
elif v ! = parent[u]:
low[u] = min (low[u], disc[v])
def bridge( self ):
visited = [ False ] * ( self .V)
disc = [ float ( "Inf" )] * ( self .V)
low = [ float ( "Inf" )] * ( self .V)
parent = [ - 1 ] * ( self .V)
for i in range ( self .V):
if visited[i] = = False :
self .bridgeUtil(i, visited, parent, low, disc)
g1 = Graph( 5 )
g1.addEdge( 1 , 0 )
g1.addEdge( 0 , 2 )
g1.addEdge( 2 , 1 )
g1.addEdge( 0 , 3 )
g1.addEdge( 3 , 4 )
print ( "Bridges in first graph " )
g1.bridge()
g2 = Graph( 4 )
g2.addEdge( 0 , 1 )
g2.addEdge( 1 , 2 )
g2.addEdge( 2 , 3 )
print ( "\nBridges in second graph " )
g2.bridge()
g3 = Graph ( 7 )
g3.addEdge( 0 , 1 )
g3.addEdge( 1 , 2 )
g3.addEdge( 2 , 0 )
g3.addEdge( 1 , 3 )
g3.addEdge( 1 , 4 )
g3.addEdge( 1 , 6 )
g3.addEdge( 3 , 5 )
g3.addEdge( 4 , 5 )
print ( "\nBridges in third graph " )
g3.bridge()
|
C#
using System;
using System.Collections.Generic;
public class Graph
{
private int V;
private List< int > []adj;
int time = 0;
static readonly int NIL = -1;
Graph( int v)
{
V = v;
adj = new List< int >[v];
for ( int i = 0; i < v; ++i)
adj[i] = new List< int >();
}
void addEdge( int v, int w)
{
adj[v].Add(w);
adj[w].Add(v);
}
void bridgeUtil( int u, bool []visited, int []disc,
int []low, int []parent)
{
visited[u] = true ;
disc[u] = low[u] = ++time;
foreach ( int i in adj[u])
{
int v = i;
if (!visited[v])
{
parent[v] = u;
bridgeUtil(v, visited, disc, low, parent);
low[u] = Math.Min(low[u], low[v]);
if (low[v] > disc[u])
Console.WriteLine(u + " " + v);
}
else if (v != parent[u])
low[u] = Math.Min(low[u], disc[v]);
}
}
void bridge()
{
bool []visited = new bool [V];
int []disc = new int [V];
int []low = new int [V];
int []parent = new int [V];
for ( int i = 0; i < V; i++)
{
parent[i] = NIL;
visited[i] = false ;
}
for ( int i = 0; i < V; i++)
if (visited[i] == false )
bridgeUtil(i, visited, disc, low, parent);
}
public static void Main(String []args)
{
Console.WriteLine( "Bridges in first graph " );
Graph g1 = new Graph(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.bridge();
Console.WriteLine();
Console.WriteLine( "Bridges in Second graph" );
Graph g2 = new Graph(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
g2.bridge();
Console.WriteLine();
Console.WriteLine( "Bridges in Third graph " );
Graph g3 = new Graph(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
g3.bridge();
}
}
|
Javascript
<script>
class Graph
{
constructor(v)
{
this .V = v;
this .adj = new Array(v);
this .NIL = -1;
this .time = 0;
for (let i=0; i<v; ++i)
this .adj[i] = [];
}
addEdge(v,w)
{
this .adj[v].push(w);
this .adj[w].push(v);
}
bridgeUtil(u,visited,disc,low,parent)
{
visited[u] = true ;
disc[u] = low[u] = ++ this .time;
for (let i of this .adj[u])
{
let v = i;
if (!visited[v])
{
parent[v] = u;
this .bridgeUtil(v, visited, disc, low, parent);
low[u] = Math.min(low[u], low[v]);
if (low[v] > disc[u])
document.write(u+ " " +v+ "<br>" );
}
else if (v != parent[u])
low[u] = Math.min(low[u], disc[v]);
}
}
bridge()
{
let visited = new Array( this .V);
let disc = new Array( this .V);
let low = new Array( this .V);
let parent = new Array( this .V);
for (let i = 0; i < this .V; i++)
{
parent[i] = this .NIL;
visited[i] = false ;
}
for (let i = 0; i < this .V; i++)
if (visited[i] == false )
this .bridgeUtil(i, visited, disc, low, parent);
}
}
document.write( "Bridges in first graph <br>" );
let g1 = new Graph(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.bridge();
document.write( "<br>" );
document.write( "Bridges in Second graph<br>" );
let g2 = new Graph(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
g2.bridge();
document.write( "<br>" );
document.write( "Bridges in Third graph <br>" );
let g3 = new Graph(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
g3.bridge();
</script>
|
Output
Bridges in first graph
3 4
0 3
Bridges in second graph
2 3
1 2
0 1
Bridges in third graph
1 6
Time Complexity: O(V+E),
- The above approach uses simple DFS along with Tarjan’s Algorithm.
- So time complexity is the same as DFS which is O(V+E) for adjacency list representation of the graph.
Auxiliary Space: O(V) is used for visited, disc and low arrays.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
02 May, 2023
Like Article
Save Article