Reputation: 1571
I have a programming task(not homework.) where I have to find the bridges in a graph. I worked on it a bit myself, but could not come up with anything satisfactory. So i googled it , I did find something but I am unable to understand the algorithm as it is presented. Could someone please take a look at this code and give me an explanation.?
public Bridge(Graph G) {
low = new int[G.V()];
pre = new int[G.V()];
for (int v = 0; v < G.V(); v++) low[v] = -1;
for (int v = 0; v < G.V(); v++) pre[v] = -1;
for (int v = 0; v < G.V(); v++)
if (pre[v] == -1)
dfs(G, v, v);
}
public int components() { return bridges + 1; }
private void dfs(Graph G, int u, int v) {
pre[v] = cnt++;
low[v] = pre[v];
for (int w : G.adj(v)) {
if (pre[w] == -1) {
dfs(G, v, w);
low[v] = Math.min(low[v], low[w]);
if (low[w] == pre[w]) {
StdOut.println(v + "-" + w + " is a bridge");
bridges++;
}
}
// update low number - ignore reverse of edge leading to v
else if (w != u)
low[v] = Math.min(low[v], pre[w]);
}
}
Upvotes: 33
Views: 28638
Reputation: 1
Lets say you are given an edge (c,d) and you have to find if it is a bridge or not
There are several methods to solve this problem but lets concentrate on one.
In the end, if you found that d is visited, this means, by removing c-d we can still visit d from the source c, hence c-d is not a bridge. Here is the short implementation of the above :
int isBridge(int V, ArrayList<ArrayList<Integer>> adj,int c,int d)
{
Queue<Integer> q = new LinkedList<>();
boolean visited[] = new boolean[V];
ArrayList<Integer> ls = new ArrayList<>();
q.add(c);
while(!q.isEmpty()) {
Integer v = q.remove();
if(visited[v])
continue;
visited[v] = true;
ls.add(v);
for(Integer e: adj.get(v)) {
if(visited[e] || (c == v && d == e))
continue;
q.add(e);
}
}
if(visited[d] == true)
return 0;
return 1;
}
Upvotes: 0
Reputation: 868
Not a new answer, but I needed this for the JVM/Kotlin. Here's a translation that relies upon com.google.common.graph.Graph
.
/**
* [T] The type of key held in the [graph].
*/
private class BridgeComputer<T>(private val graph: ImmutableGraph<T>) {
/**
* Counter.
*/
private var count = 0
/**
* `low[v]` = Lowest preorder of any vertex connected to `v`.
*/
private val low: MutableMap<T, Int> =
graph.nodes().map { it to -1 }.toMap(mutableMapOf())
/**
* `pre[v]` = Order in which [depthFirstSearch] examines `v`.
*/
private val pre: MutableMap<T, Int> =
graph.nodes().map { it to -1 }.toMap(mutableMapOf())
private val foundBridges = mutableSetOf<Pair<T, T>>()
init {
graph.nodes().forEach { v ->
// DO NOT PRE-FILTER!
if (pre[v] == -1) {
depthFirstSearch(v, v)
}
}
}
private fun depthFirstSearch(u: T, v: T) {
pre[v] = count++
low[v] = checkNotNull(pre[v]) { "pre[v]" }
graph.adjacentNodes(v).forEach { w ->
if (pre[w] == -1) {
depthFirstSearch(v, w)
low[v] =
Math.min(checkNotNull(low[v]) { "low[v]" }, checkNotNull(low[w]) { "low[w]" })
if (low[w] == pre[w]) {
println("$v - $w is a bridge")
foundBridges += (v to w)
}
} else if (w != u) {
low[v] =
Math.min(checkNotNull(low[v]) { "low[v]" }, checkNotNull(pre[w]) { "pre[w]" })
}
}
}
/**
* Holds the computed bridges.
*/
fun bridges() = ImmutableSet.copyOf(foundBridges)!!
}
Hopefully this makes someone's life easier.
Upvotes: 2
Reputation: 383
Not a new answer, but I needed this in Python. Here's a translation of the algorithm for an undirected NetworkX Graph object G
:
def bridge_dfs(G,u,v,cnt,low,pre,bridges):
cnt += 1
pre[v] = cnt
low[v] = pre[v]
for w in nx.neighbors(G,v):
if (pre[w] == -1):
bridge_dfs(G,v,w,cnt,low,pre,bridges)
low[v] = min(low[v], low[w])
if (low[w] == pre[w]):
bridges.append((v,w))
elif (w != u):
low[v] = min(low[v], pre[w])
def get_bridges(G):
bridges = []
cnt = 0
low = {n:-1 for n in G.nodes()}
pre = low.copy()
for n in G.nodes():
bridge_dfs(G, n, n, cnt, low, pre, bridges)
return bridges # <- List of (node-node) tuples for all bridges in G
Be careful of Python's recursion depth limiter for large graphs...
Upvotes: 3
Reputation: 1747
Def: Bridge is an edge, when removed, will disconnect the graph (or increase the number of connected components by 1).
One observation regarding bridges in graph; none of the edges that belong to a loop can be a bridge. So in a graph such as A--B--C--A
, removing any of the edge A--B
, B--C
and C--A
will not disconnect the graph. But, for an undirected graph, the edge A--B
implies B--A
; and this edge could still be a bridge, where the only loop it is in is A--B--A
. So, we should consider only those loops formed by a back edge. This is where the parent information you've passed in the function argument helps. It will help you to not use the loops such as A--B--A
.
Now to identify the back edge (or the loop), A--B--C--A
we use the low
and pre
arrays. The array pre
is like the visited
array in the dfs algorithm; but instead of just flagging that the vertex as visited, we identify each vertex with a different number (according to its position in the dfs tree). The low
array helps to identify if there is a loop. The low
array identifies the lowest numbered (from pre
array) vertex that the current vertex can reach.
Lets work through this graph A--B--C--D--B
.
Starting at A
dfs: ^ ^ ^ ^ ^
pre: 0 -1 -1 -1 -1 0--1 -1 -1 1 0--1--2 -1 1 0--1--2--3 1 0--1--2--3--1
graph: A--B--C--D--B A--B--C--D--B A--B--C--D--B A--B--C--D--B A--B--C--D--B
low: 0 -1 -1 -1 -1 0--1 -1 -1 1 0--1--2 -1 1 0--1--2--3 1 0--1--2--3->1
At this point, you've encountered a cycle/loop in graph. In your code if (pre[w] == -1)
will be false this time. So, you'll enter the else part. The if statement there is checking if B
is the parent vertex of D
. It is not, so D
will absorb B
's pre
value into low
. Continuing the example,
dfs: ^
pre: 0--1--2--3
graph: A--B--C--D
low: 0--1--2--1
This low
value of D
propagates back to C
through the code low[v] = Math.min(low[v], low[w]);
.
dfs: ^ ^ ^
pre: 0--1--2--3--1 0--1--2--3--1 0--1--2--3--1
graph: A--B--C--D--B A--B--C--D--B A--B--C--D--B
low: 0--1--1--1--1 0--1--1--1--1 0--1--1--1--1
Now, that the cycle/loop is identified, we note that the vertex A
is not part of the loop. So, you print out A--B
as a bridge. The code low['B'] == pre['B']
means an edge to B
will be a bridge. This is because, the lowest vertex we can reach from B
is B
itself.
Hope this explanation helps.
Upvotes: 84