寻找无向连通图的割点
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数组值。
辅助类Bag
要寻找无向连通图中所有的关节点,比较便捷的方法是利用一次深度优先遍历,找到所有关节点
对于节点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数组值。
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |
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; } } }
相关文章推荐
- touch详解
- java日志组件介绍(common-logging,log4j,slf4j,logback )
- 破了我的设计模式的处——痛苦并快乐着
- [Android] Otto源码简析
- 网络访问层
- Centos 6.3下升级subversion版本到1.7.x
- decorator模式
- iOS常用第三方库
- php的基本语法与字符串与增删改查
- JS设置cookie,读取cookie,删除cookie
- C++编译错误:multiple types in one declaration
- Perfect Squares
- 006 - ZigZag Conversion
- 第五章 处理器拦截器详解——跟着开涛学SpringMVC
- android监听应用安装,如判断是新安装的应用,还是覆盖安装的应用
- JAVA字符串格式化-String.format()的使用
- BAT解密:互联网技术发展之路(7)- 网络层技术剖析
- BAT解密:互联网技术发展之路(6)- 服务层技术剖析
- 针对于一个独立car的js做的后台对cookie与数据库转换处理
- Xilinx DDR3 IP核使用问题汇总(持续更新)和感悟