题目:求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通,描述算法。
分析:
1. 最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点,图不再连通,则此点是割点,反之不是割点(图的连通性一般通过深搜来判定,是否能一次搜索完 全部顶点);
2. 通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类割点的特性:
(1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为割点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林;
(2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为割点。因为删去v,则其子树和图的其它部分被分割开来。
仍然利用深搜算法,只不过在这里定义visited[v]表示为深度优先搜索遍历图时访问顶点v的次序号,定义low[v]=Min{visited[v],low[w],visited[k]},其中w是顶点v在深度优先生成树上的孩子节点;k是顶点v在深度优先生成树上由回边联结的祖先节点。
割点判定条件:如果对于某个顶点v,存在孩子节点w且low[w]>=visited[v],则该顶点v必为关节点。因为当w是v的孩子节点时,low[w]>=visited[v],表明w及其子孙均无指向v的祖先的回边,那么当删除顶点v后,v的孩子节点将于其他节点被分割开来,从来形成新的连通分量。
证明:
割点集的定义:如果在连通图G中去掉某一点后图不连通,那么这个点即为G的割点,所有割点的集合即为点割集。
求点割集的方法:利用tarjan算法的思想,用数组dfn[v]存储DFS遍历到点v的时间,数组low[v]存储点v能追溯到最早的祖先节点。
如果对于点v来说有如下结论:
1.如果点v是DFS序列的根节点,则如果v有一个以上的孩子,则v是一个割点。
2.如果v不是DFS序列根节点,并且点v的任意后继u能追溯到最早的祖先节点low[u]>=dfn[v],则v是一个割点。
证明1:
假设DFS遍历的第一个节点v不是割点,那么则有low[v]=dfn[v]=1,继续对v的孩子节点u遍历,必然有low[u]>=dfn[v],按照第二条性质,则v是割点,但我们已经假设v不是割点。这是由于v是DFS遍历的起始节点,在遍历序列中v没有祖先节点,v的所有后继节点能追溯到最早的祖先节点最多也就是v了,不可能比v再早了,因此必须把DFS遍历的第一个节点v单独考虑,那么怎么判断v是不是割点呢?
例如上图,设v是DFS序列访问的第一个节点,对v的孩子节点u和u的所有孩子节点进行DFS遍历并标记为已经访问后,如果v的另一个孩子节点k没有被标记为已经访问,那么u和k之间一定不存在边,也就是说u和k之间的连通必然需要点v,因此如果v是DFS遍历的第一个节点,对v是否为割点的判断方法是:看v是不是有多个孩子,如果有则v是割点。
证明2:
如果v不是DFS遍历的第一个节点,那么对于v的所有后继节点来说,如果v不是割点(也就是如果删掉点v,剩下的图还是连通图),那么v的后继节点必然能追溯到DFS遍历序列中v的祖先节点,也就是v的后继节点中存在到达DFS序列中v的祖先的路径,因此当DFS回溯到v节点时对于v的所有后继节点u来说,都有low[u]<dfn[v]。
如果v是一个割点,对所有v的后继节点u进行DFS后,必然有low[u]>=dfn[v],这是因为,当遍历v并将其锁定后,到达v的祖先节点的路径已经被封死,v的后继节点必然不可能访问到v的祖先节点,因此,必然有low[u]>=dfn[v]。