一些概念:
- 强连通图: 如果 在一个有向图G中,每两个点都强连通,我们就叫这个图,强连通图。
- 强连通分量(strongly connected components):在一个有向图G中,有一个子图,这个子图每2个点都满足强连通,我们就叫这个子图叫做强连通分量。
- 割点:一个结点称为割点(或者割顶)当且仅当去掉该节点极其相关的边之后的子图不连通。
- 桥:一条边称为桥(或者割边)当且仅当去掉该边之后的子图不连通。
- dfn[]:保存这个点被第几次搜到。
- low[]:保存这个点在或其子树能够追溯到的最早的栈中节点的次序号。
强连通分量:
1 | void tarjan(int u){ |
割点:
用cut[]记录这个点是否为割点。
对于根节点,计算其子树数量,如果有2棵即以上的子树,就是割点。因为如果去掉这个点,这两棵子树就不能互相到达。
对于非根节点,如果low[v]>=dfn[u],此时u就是割点。
1 | void tarjan(int u,int fa) { |
桥:
与割点相似,把low[v]>=dfn[u]换成low[v]>dfn[u](因为不能包括自己)
1 | void tarjan(int u,int fa) { |
缩点
缩点就是把一个强连通分量看做一个点。
我们用染色来区分每个点属于哪个强连通分量。
对于缩点后的边有两种处理方式:
- 缩点后枚举每条边,两端点是否属于同一强连通分量,若不属于则建边。
- 在缩点时每个点出栈时把这个点的边传给它的强连通分量,使其强连通分量指向某个点(注意是缩点前的点)到后面遍历整张图时判断它所指向的点的颜色是否与自己相同。注意此时可能有不止一条边在两个强连通分量之间,所以要标记判断。
鉴于第一种实现方法太简单,这里给出第二种的实现方法:
1 | void tarjan(int u){ |