寻找无向连通图的割点

无向连通图的割点又被成为关节点(articulation point), 移除关节点,则原连通图变成两个连通分量, 一个没有关节点的连通图被成为重连通图 (biconnected graph)

要寻找无向连通图中所有的关节点,比较便捷的方法是利用一次深度优先遍历,找到所有关节点

对于节点u,及其子节点v,  u->v, 可以用数组dfn[u]来表示当前u的遍历序列号,用low[u]表示u及u的子节点通过非tree edge所能找到的最早的祖先节点的序列号, 如果u是关节点,则有两种情况:

1. 如果u是根节点,且u有两棵及以上的子树,则节点u为关节点,很明显,移除u会使其两棵子树变成不连通的两个连通分量

2. 如果对于节点v, low[v]的值 >= dfn[u], 说明v及其子节点最多能指到节点u, 没有其他路径能指到u的祖先,则移除u,其子节点v会成为独立的连通分量

得到公式:  low[u] = min (

          dfn[u],

          low[v],  u -> v 是tree edge, 即节点v以前未被dfs遍历过, 此时low[u] = min(low[u], low[v])

          dfn[v],  u -> v 是back edge, 即节点v已经被访问过, 此时low[u] = min(low[u], dfn[v]),

          为什么不是low[v]而是dfn[v], 因为此时节点v已经被访问过了,说明 u->v是条回边,v是当前节点u的祖先,我们直接取该祖先的遍历序列值即可

            )

下表给出图(a)对应的dfn与low数组值。

i0123456789101112
vertex A B C D E F G H I J K L M
dfn[i] 1 5 12 10 11 13 8 6 9 4 7 2 3
low[i] 1 1 1 5 5 1 5 5 8 2 5 1 1
 1 package com.rui.microsoft;
 2 
 3 public class Test39_FindCutPoints {
 4 
 5     public static void main(String[] args) {
 6         UndirectedGraph dGraph = new UndirectedGraph(5);
 7         dGraph.addEdge(0, 1);
 8         dGraph.addEdge(1, 2);
 9         dGraph.addEdge(2, 0);
10         dGraph.addEdge(0, 3);
11         dGraph.addEdge(3, 4);
12         dGraph.tarjan(0);
13         
14         for(int i = 0; i < dGraph.V; i++){
15             if(dGraph.APs[i]){
16                 System.out.println(" " + i);
17             }
18         }
19     }
20 }
21 
22 class UndirectedGraph{
23     
24     int V;
25     Bag<Integer>[] adj;
26     
27     boolean[] visited;
28     int[] dfn;
29     int[] low;
30     int[] parents;
31     
32     boolean[] APs;
33     
34     int order = 0;
35     
36     public UndirectedGraph(int size) {
37         this.V = size;
38         this.adj = new Bag[size];
39         
40         this.dfn = new int[size];
41         this.low = new int[size];
42         this.parents = new int[size];
43         this.visited = new boolean[size];
44         this.APs = new boolean[size];
45         
46         for(int i = 0; i < size; i++){
47             this.adj[i] = new Bag<Integer>();
48             this.parents[i] = -1;
49             this.APs[i] = false;
50         }
51     }
52     
53     void addEdge(int from, int to){
54         adj[from].add(to);
55         adj[to].add(from);
56     }
57     
58     void tarjan(int u){
59         dfn[u] = low[u] = ++order;
60         visited[u] = true;
61         int childs = 0;
62         
63         //dfs
64         for(int v: this.adj[u]){
65             if(!visited[v]){
66                 childs++;
67                 parents[v] = u;
68                 tarjan(v);
69                 
70                 //after dfs the subtree of v
71                 low[u] = min(low[u], low[v]);
72                 
73                 //check
74                 if(parents[u] == -1 && childs > 1){
75                     APs[u] = true;
76                 }
77                 
78                 if(parents[u] != -1 && dfn[u] <= low[v]){
79                     APs[u] = true;
80                 }
81             }else{
82                 //back edge
83                 low[u] = min(low[u], dfn[v]);
84             }
85         }
86     }
87     
88     int min(int a, int b){
89         return a<b? a: b;
90     }
91 }

辅助类Bag

 1 package com.rui.microsoft;
 2 
 3 import java.util.Iterator;
 4 import java.util.NoSuchElementException;
 5 
 6 public class Bag<Item> implements Iterable<Item>{
 7     
 8     private Node<Item> first;
 9     private int N;
10     
11     private static class Node<Item>{
12         private Item item;
13         private Node<Item> next;
14     }
15     
16     public Bag(){
17         first = null;
18         N = 0;
19     }
20     
21     public boolean isEmpty(){
22         return first == null;
23     }
24     
25     public int size(){
26         return N;
27     }
28     
29     public void add(Item item){
30         Node<Item> oldFirst = first;
31         first = new Node<Item>();
32         first.item = item;
33         first.next = oldFirst;
34         N++;
35     }
36     
37     @Override
38     public Iterator<Item> iterator() {
39         return new ListIterator<Item>(first);
40     }
41     
42     private class ListIterator<Item> implements Iterator<Item> {
43         private Node<Item> current;
44 
45         public ListIterator(Node<Item> first) {
46             current = first;
47         }
48 
49         public boolean hasNext()  { return current != null;                     }
50         public void remove()      { throw new UnsupportedOperationException();  }
51 
52         public Item next() {
53             if (!hasNext()) throw new NoSuchElementException();
54             Item item = current.item;
55             current = current.next; 
56             return item;
57         }
58     }
59     
60 }
原文地址:https://www.cnblogs.com/aalex/p/4956425.html