如果一个连通的无向图的任意顶点删除后,剩下的图仍然连通,该图被称为双连通的。
如果一个图不是双连通的,那么那些将其删除后不再连通的节点,被称为割裂点。
我们可以用深度优先生成树来寻找割裂点,起点为树根,每向前搜索到一个点就会产生一条前向边,但有时会遇到回路,即搜索到经过的点,这时产生的边称为背向边,背向边并不属于生成树,但会在后面用到。
假设每个顶点有两个编号:一个是遍历时的序号,另一个比较令人费解,被称为最低编号,某点的最低编号大概可以定义为:从该点通过0条或多条前向边或背向边所能达到的序号最低的点的序号。
绕了一圈,终于可以回到寻找割裂点的问题,什么是割裂点呢?
1)当树根有两个以上的儿子时,它就是割裂点
2)对于其它点,它是割裂点当且仅当它有某个儿子的最低编号大于等于它自己的序号
为什么会是这样? 原书给出了“当”的证明,“仅当”则留作了课后作业,我没做,假定是对的吧!
最后的实现反而倒简单,原书给出了部分伪代码,大致思路如下:
1)将图装入一个邻接表, 从起点开始遍历
2)设置当前点的序号,暂时令最低编号等于序号
3)向前搜索第一个邻接点,如果产生前向边,则从该邻接点递归向前搜索,直到无路可走后依次返回,归途中一边检测当前点是否割裂点,一边调整当前点的最低编号。如果产生背向边,则只调整当前点的最低编号
4)反复执行第三步,直到所有邻接点搜索完成
下面是对原书中示例的求解,运行结果如下: