您的位置:首页 > 其它

寻找无向连通图的割点

2015-11-11 16:48 246 查看
无向连通图的割点又被成为关节点(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
vertexABCDEFGHIJKLM
dfn[i]15121011138694723
low[i]1115515582511
package com.rui.microsoft;

public class Test39_FindCutPoints {

public static void main(String[] args) {
UndirectedGraph dGraph = new UndirectedGraph(5);
dGraph.addEdge(0, 1);
dGraph.addEdge(1, 2);
dGraph.addEdge(2, 0);
dGraph.addEdge(0, 3);
dGraph.addEdge(3, 4);
dGraph.tarjan(0);

for(int i = 0; i < dGraph.V; i++){
if(dGraph.APs[i]){
System.out.println(" " + i);
}
}
}
}

class UndirectedGraph{

int V;
Bag<Integer>[] adj;

boolean[] visited;
int[] dfn;
int[] low;
int[] parents;

boolean[] APs;

int order = 0;

public UndirectedGraph(int size) {
this.V = size;
this.adj = new Bag[size];

this.dfn = new int[size];
this.low = new int[size];
this.parents = new int[size];
this.visited = new boolean[size];
this.APs = new boolean[size];

for(int i = 0; i < size; i++){
this.adj[i] = new Bag<Integer>();
this.parents[i] = -1;
this.APs[i] = false;
}
}

void addEdge(int from, int to){
adj[from].add(to);
adj[to].add(from);
}

void tarjan(int u){
dfn[u] = low[u] = ++order;
visited[u] = true;
int childs = 0;

//dfs
for(int v: this.adj[u]){
if(!visited[v]){
childs++;
parents[v] = u;
tarjan(v);

//after dfs the subtree of v
low[u] = min(low[u], low[v]);

//check
if(parents[u] == -1 && childs > 1){
APs[u] = true;
}

if(parents[u] != -1 && dfn[u] <= low[v]){
APs[u] = true;
}
}else{
//back edge
low[u] = min(low[u], dfn[v]);
}
}
}

int min(int a, int b){
return a<b? a: b;
}
}


辅助类Bag

package com.rui.microsoft;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Bag<Item> implements Iterable<Item>{

private Node<Item> first;
private int N;

private static class Node<Item>{
private Item item;
private Node<Item> next;
}

public Bag(){
first = null;
N = 0;
}

public boolean isEmpty(){
return first == null;
}

public int size(){
return N;
}

public void add(Item item){
Node<Item> oldFirst = first;
first = new Node<Item>();
first.item = item;
first.next = oldFirst;
N++;
}

@Override
public Iterator<Item> iterator() {
return new ListIterator<Item>(first);
}

private class ListIterator<Item> implements Iterator<Item> {
private Node<Item> current;

public ListIterator(Node<Item> first) {
current = first;
}

public boolean hasNext()  { return current != null;                     }
public void remove()      { throw new UnsupportedOperationException();  }

public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: