对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点(又称割顶)。
如果我们尝试删除每个点,并且判断这个图的连通性,那么复杂度会特别高。所以要介绍一个常用的算法:Tarjan。
首先,我们上一个图:
很容易看出割点是 2,而且这个图仅有这一个割点。
首先,我们按照 DFS 序给他打上时间戳(访问的顺序)。
这些信息被我们保存在一个叫做 num
的数组中。
还需要另外一个数组 low
,用它来存储不经过其父亲能到达的最小的时间戳。
例如 low[2]
的话是 1,low[5]
和 low[6]
是 3。
然后我们开始 DFS,我们判断某个点是否是割点的根据是:对于某个顶点 $u$,如果存在至少一个顶点 $v$($u$ 的儿子),使得 $low_v\ge num_u$,即不能回到祖先,那么 $u$ 点为割点。
另外,如果搜到了自己(在环中),如果它有两个及以上的儿子,那么它一定是割点了,如果只有一个儿子,那么把它删掉,不会有任何的影响。比如下面这个图,此处形成了一个环,从树上来讲它有 2 个儿子:
我们在访问 1 的儿子的时候,假设先 DFS 到了 2,然后标记用过,然后递归往下,来到了 4,4 又来到了 3,当递归回溯的时候,会发现 3 已经被访问过了,所以不是割点。
更新 low
的伪代码如下:
如果 v 是 u 的儿子 low[u] = min(low[u], low[v]); 否则 low[u] = min(low[u], num[v]);
题意:求割点
代码:
题意:选定一个结点,使得删掉它之后的连通块数量最多
题解:对于根结点,删掉它之后新增连通块为其儿子数-1;对于非根结点的割点,删掉它之后新增的连通块等于其儿子数。
代码:
和割点差不多,叫做桥。
对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边。严谨来说,就是:假设有连通图 $G=\{V,E\}$,$e$ 是其中一条边(即 $e\in E$),如果 $G-e$ 是不连通的,则边 $e$ 是图 $G$ 的一条割边(桥)。
比如说,下图中,
红色箭头指向的就是割边。
和割点差不多,只要改一处:$low_v>num_u$ 就可以了,而且不需要考虑根结点的问题。
割边是和是不是根结点没关系的,原来我们求割点的时候是指点 $v$ 是不可能不经过父结点 $u$ 回到祖先结点(包括父结点),所以顶点 $u$ 是割点。如果 $low_v=num_u$ 表示还可以回到父结点,如果顶点 $v$ 不能回到祖先也没有另外一条回到父亲的路,那么 $u-v$ 这条边就是割边。
下面代码实现了求割边,其中,当 isbridge[x]
为真时,(father[x],x)
为一条割边。