104 lines
2.7 KiB
Java
104 lines
2.7 KiB
Java
import java.util.*;
|
|
import java.util.stream.Stream;
|
|
|
|
public class Biconnectivity {
|
|
|
|
List<Integer>[] graph;
|
|
boolean[] visited;
|
|
Stack<Integer> stack;
|
|
int time;
|
|
int[] tin;
|
|
int[] lowlink;
|
|
List<List<Integer>> edgeBiconnectedComponents;
|
|
List<Integer> cutPoints;
|
|
List<String> bridges;
|
|
|
|
public List<List<Integer>> biconnectivity(List<Integer>[] graph) {
|
|
int n = graph.length;
|
|
this.graph = graph;
|
|
visited = new boolean[n];
|
|
stack = new Stack<>();
|
|
time = 0;
|
|
tin = new int[n];
|
|
lowlink = new int[n];
|
|
edgeBiconnectedComponents = new ArrayList<>();
|
|
cutPoints = new ArrayList<>();
|
|
bridges = new ArrayList<>();
|
|
|
|
for (int u = 0; u < n; u++)
|
|
if (!visited[u])
|
|
dfs(u, -1);
|
|
|
|
return edgeBiconnectedComponents;
|
|
}
|
|
|
|
void dfs(int u, int p) {
|
|
visited[u] = true;
|
|
lowlink[u] = tin[u] = time++;
|
|
stack.add(u);
|
|
int children = 0;
|
|
boolean cutPoint = false;
|
|
for (int v : graph[u]) {
|
|
if (v == p)
|
|
continue;
|
|
if (visited[v]) {
|
|
lowlink[u] = Math.min(lowlink[u], tin[v]); // or lowlink[u] = Math.min(lowlink[u], lowlink[v]);
|
|
} else {
|
|
dfs(v, u);
|
|
lowlink[u] = Math.min(lowlink[u], lowlink[v]);
|
|
cutPoint |= tin[u] <= lowlink[v];
|
|
if (tin[u] < lowlink[v]) // or if (lowlink[v] == tin[v])
|
|
bridges.add("(" + u + "," + v + ")");
|
|
++children;
|
|
}
|
|
}
|
|
if (p == -1)
|
|
cutPoint = children >= 2;
|
|
if (cutPoint)
|
|
cutPoints.add(u);
|
|
if (tin[u] == lowlink[u]) {
|
|
List<Integer> component = new ArrayList<>();
|
|
while (true) {
|
|
int x = stack.pop();
|
|
component.add(x);
|
|
if (x == u)
|
|
break;
|
|
}
|
|
edgeBiconnectedComponents.add(component);
|
|
}
|
|
}
|
|
|
|
// tree of edge-biconnected components
|
|
public static List<Integer>[] ebcTree(List<Integer>[] graph, List<List<Integer>> components) {
|
|
int[] comp = new int[graph.length];
|
|
for (int i = 0; i < components.size(); i++)
|
|
for (int u : components.get(i))
|
|
comp[u] = i;
|
|
List<Integer>[] g = Stream.generate(ArrayList::new).limit(components.size()).toArray(List[]::new);
|
|
for (int u = 0; u < graph.length; u++)
|
|
for (int v : graph[u])
|
|
if (comp[u] != comp[v])
|
|
g[comp[u]].add(comp[v]);
|
|
return g;
|
|
}
|
|
|
|
// Usage example
|
|
public static void main(String[] args) {
|
|
List<Integer>[] graph = Stream.generate(ArrayList::new).limit(6).toArray(List[]::new);
|
|
|
|
int[][] esges = {{0, 1}, {1, 2}, {0, 2}, {2, 3}, {1, 4}, {4, 5}, {5, 1}};
|
|
for (int[] edge : esges) {
|
|
graph[edge[0]].add(edge[1]);
|
|
graph[edge[1]].add(edge[0]);
|
|
}
|
|
|
|
Biconnectivity bc = new Biconnectivity();
|
|
List<List<Integer>> components = bc.biconnectivity(graph);
|
|
|
|
System.out.println("edge-biconnected components:" + components);
|
|
System.out.println("cut points: " + bc.cutPoints);
|
|
System.out.println("bridges:" + bc.bridges);
|
|
System.out.println("condensation tree:" + Arrays.toString(ebcTree(graph, components)));
|
|
}
|
|
}
|