Given an undirected connected graph, check if the graph is 2–edge connected and return the bridges (if any).

A connected graph is 2–edge connected if it remains connected whenever any edges are removed. A bridge (or cut arc) is an edge of a graph whose deletion increases its number of connected components, i.e., an edge whose removal disconnects the graph. So if any such bridge exists, the graph is not 2–edge connected.

For example, the following graph has 6 vertices and 3 bridges (highlighted in red):

 
2–edge connected graph

Practice this problem

Prerequisite:

Types of edges involved in DFS and relation between them

Arrival and departure time of vertices in DFS

 
A simple approach would be to remove each edge from the graph one by one and run Depth–first search (DFS) or Breadth–first search (BFS) starting from any vertex. If the DFS or BFS covers all nodes in the graph, then the removed edge cannot be a bridge. If not, that edge is a bridge. The time complexity of this solution is O(E × (V + E)), where V and E are the total number of vertices and edges in the graph, respectively.

 
We can solve this problem efficiently in one pass of DFS. When we do a DFS from vertex v in an undirected graph, there could be edges going out of the subtree, i.e., back edges. We can say that the graph is 2–edge connected if and only if for every edge u —> v in the graph, there is at least one back-edge that is going out of a subtree rooted at v to some ancestor of u. When we say subtree rooted at v, we mean all of v's descendants, including the vertex itself.

In other words, when we backtrack from a vertex v, we need to ensure that there is some back-edge from some descendant of v (including v) to some proper ancestor (parent or above) of v.

How can we modify DFS so that we can check if there is a back-edge going out of every subtree?

We can modify DFS such that DFS(v) returns the smallest arrival time to which there is a back edge from the subtree rooted at v. For example, let arrival(v) be the arrival time of vertex v in the DFS. If there is a back edge out of the subtree rooted at v, it is to something visited before v, and therefore with a smaller arrival value. Remember for a back edge u —> v in a graph, arrival[u] > arrival[v].

Suppose four edges are going out of a subtree rooted at v to vertex a, b, c and d, with arrival time A(a), A(b), A(c) and A(d), respectively. We look at their four arrival times and consider the smallest among them, that will be the value returned by DFS(v), i.e., DFS(v) returns the minimum min of A(a), A(b), A(c), and A(d). But before returning, we have to check that min is less than the A(v). If min is less than the A(v), then that means that at least one back-edge is going out of the subtree rooted at v. If not, we can say that (parent[v], v) is a bridge.

The algorithm can be implemented as follows in C++, Java, and Python:

C++


Download  Run Code

Output:

Bridges are (0, 2) (2, 1) (3, 5)

Java


Download  Run Code

Output:

Bridges are [(0, 2), (2, 1), (3, 5)]

Python


Download  Run Code

Output:

Bridges are {(0, 2), (2, 1), (3, 5)}

 
The time complexity of the above solution is O(V + E), where V and E are the total number of vertices and edges in the graph, respectively.

 
Reference: Dr. Naveen Garg, IIT–D (Lecture – 28 Applications of DFS)

 
Image credits: http://mathworld.wolfram.com/GraphBridge.html