Undirected graph
In the following undirected graph
- An edge
of an undirected graph is a bridge if and only if lies on no cycle of - Every edge of an undirected tree is a bridge
Let
- let
and be two vertices of the dfs such that is an antecesor of , also and are not adjacent- if there’s a back edge
then none of the edges in the path are bridges, if we remove one of them the graph is still connected because of this edge - otherwise the edge is a bridge
- if there’s a back edge
Implementation notes
- to check if a succesor of a vertex
has a back edge to a predecessor of an additional state is stored in each vertex which is the discovery time of the lowest back edge of a successor of (by lowest back edge we mean the back edge to a vertex with the lowest discovery time) denoted as , initially this state is set to the discovery time of the vertex i.e. , this state is propagated when the backtracking is performed - let
be a back edge, when this edge is analyzed the state needs to be updated to be the minimum between the existing and the discovery time of , i.e. - let
be an adjacent successor of in the dfs tree, when we’ve finished analyzing the branch of the tree because of the edge we have to check if the state contains a back edge to some predecessor of ( is propagated) i.e. , if so then is not a bridge
int time_spent;
// the adjacency list representation of `G`
vector<vector<int> > g;
// the time a vertex `i` was discovered first
vector<int> time_in;
// stores the discovery time of the lowest predecessor that vertex `i`'s
// succesor vertices can reach **through a back edge**, initially
// the lowest predecessor is set to the vertex itself
vector<int> back;
// the bridges found during the dfs
vector<pair<int, int> > cut_edge;
void dfs(int v, int parent) {
// the lowest back edge discovery time of `v` is
// set to the discovery time of `v` initally
back[v] = time_in[v] = ++time_spent;
for (int i = 0; i < g[v].size(); i += 1) {
int next = g[v][i];
if (next == parent) {
continue;
}
if (time_in[next] == -1) {
dfs(next, v);
// if there's a back edge between a descendant of `next` and
// a predecessor of `v` then `next` will have a lower back edge discovery time
// otherwise it's a bridge
if (back[next] > time_in[v]) {
cut_edge.push_back(pair<int, int> (v, next));
}
// propagation of the lowest back edge discovery time
back[v] = min(back[v], back[next]);
} else {
// *back edge*
// update the lowest back edge discovery time of `v`
back[v] = min(back[v], time_in[next]);
}
}
}
/**
* Finds the bridges in an undirected graph `G` of order `n` and size `m`
*
* Time complexity: O(n + m)
* Space complexity: O(n)
*/
void bridges() {
int n = g.size();
time_spent = 0;
time_in.assign(n, -1);
back.assign(n, -1);
cut_edge.clear();
for (int i = 0; i < n; i += 1) {
if (time_in[i] == -1) {
dfs(i, -1);
}
}
}
Directed graph (strong bridges)
Let
The following is a connected graph
A trivial algorithm to find the strong bridges of a digraph
- Compute the number of strongly connected componentes of
denoted as - For each edge
- remove
from - compute the number of strongly connected components of
denoted as - if
then is a bridge
The time complexity of the algorithm above is clearly
Let
http://www.sofsem.cz/sofsem12/files/presentations/Thursday/GiuseppeItaliano.pdf