From f5321cf81dfb7032bcfa379407f0ba1411bb88e5 Mon Sep 17 00:00:00 2001 From: bjorn-martinsson Date: Mon, 25 Sep 2023 22:29:21 +0200 Subject: [PATCH] Specified node BCC or edge BCC --- pyrival/graphs/{bcc.py => edge_bcc.py} | 3 +- pyrival/graphs/node_bcc.py | 62 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) rename pyrival/graphs/{bcc.py => edge_bcc.py} (93%) create mode 100644 pyrival/graphs/node_bcc.py diff --git a/pyrival/graphs/bcc.py b/pyrival/graphs/edge_bcc.py similarity index 93% rename from pyrival/graphs/bcc.py rename to pyrival/graphs/edge_bcc.py index 01e1eda..307b29b 100644 --- a/pyrival/graphs/bcc.py +++ b/pyrival/graphs/edge_bcc.py @@ -33,7 +33,8 @@ def find_SCC(graph): """ Given an undirected simple graph, find_BCC returns a list of lists -containing the biconnected components of the graph. Runs in O(n + m) time. +containing the edge biconnected components of the graph (i.e. no bridges). +Runs in O(n + m) time. """ def find_BCC(graph): d = 0 diff --git a/pyrival/graphs/node_bcc.py b/pyrival/graphs/node_bcc.py new file mode 100644 index 0000000..bc43c60 --- /dev/null +++ b/pyrival/graphs/node_bcc.py @@ -0,0 +1,62 @@ +""" +Given an undirected graph, + + 1 4 7 10 + / \ / \ / \ / +2 0 5 9 + \ / \ / \ / + 3 6 8 + +the cut_tree function returns the cut-block tree made out of 2 sets of nodes, the original +nodes U in the graph and new nodes V corresponding to each node biconnected component. +There is an edge between (u,v) for u in U and v in V if u lies in bicomponent v. +In the case of an unconnected graph, the function returns a forest of block-cut trees. +For the graph above, this is the tree returned by cut_tree + + 1 4 7 10 + | | | | +2--(14)--0--(13)--5--(12)--9--(11) + | | | + 3 6 8 + +Here the nodes in () denotes bicomponent nodes. +""" +def cut_tree(graph): + n = len(graph) + new_graph = [[] for _ in range(n)] + + P = [-1] * n + depth = [-1] * n + biconnect = [None] * n + root = 0 + + preorder = [] + stack = [root] + while stack: + node = stack.pop() + if depth[node] >= 0: + continue + depth[node] = len(preorder) + preorder.append(node) + for nei in graph[node]: + if depth[nei] == -1: + P[nei] = node + stack.append(nei) + preorder.pop(0) + + for node in reversed(preorder): + depth[node] = min(depth[nei] for nei in graph[node]) + if depth[P[node]] == depth[node]: + bicon = biconnect[node] = [P[node], node] + new_graph.append(bicon) + + for node in preorder: + if biconnect[node] is None: + bicon = biconnect[node] = biconnect[P[node]] + bicon.append(node) + + for bicon_ind in range(n, len(new_graph)): + for node in new_graph[bicon_ind]: + new_graph[node].append(bicon_ind) + + return new_graph