有向图 DFS 生成树

cca-1

有向图的搜索树主要有种边(不一定全部出现):

  1. 树边(tree edge):绿色边,每次搜索找到一个还没有访问过的结点的时候就形成了一条树边。
  2. 反祖边(back edge):黄色边,也被叫做回边,即指向祖先结点的边。
  3. 横叉边(cross edge):红色边,它主要是在搜索的时候遇到了一个已经访问过的结点,但是这个结点并不是当前结点的祖先时形成的。
  4. 前向边(forward edge):蓝色边,它是在搜索的时候遇到子树中的结点的时候形成的。

强连通分量

强连通图:对于有向图,如果对于任意结点,存在一条的有向简单路径,也存在一条的有向简单路径,则称是强连通图。

强连通分量:另外,对于有向图点集的一个子集,如果关于的导出子图是强连通图,则称的强连通分量。

我们考虑 DFS 生成树与强连通分量之间的关系。

如果结点是某个强连通分量在 DFS 树中遇到的第一个结点(这通常被称为这个强连通分量的根),那么这个强连通分量的其余结点一定在 DFS 树中以为根的子树中。

证明:反证法。假设有个结点在该强连通分量中但是不在以为根的子树中,那么的路径中肯定有一条离开子树的边。但是这样的边只可能是横叉边或者反祖边,然而这两条边都要求指向的结点已经被访问过了,这就和是第一个访问的结点矛盾了。

Tarjan 算法:

TARJAN(int u,int k)
    vis[u]=true
    low[u]=dfn[u]=k
    将 u 圧入栈中
    for 与 u 相邻的结点 v
        if 结点 v 未被访问过
            TARJAN(v,k+1)// 搜索
            low[u]=min(low[u],low[v])// 回溯
        else if v 在栈中
            low[u]=min(low[u],dfn[v])
    if low[u] = dfn[u]
    	则将栈中 u 以及 u 之上的结点全部弹出
    	这些结点构成一个强连通分量

无向图 DFS 生成树

cca-2

DFS 生成树:即对图进行 DFS 遍历时所有递归到的边组成的树。

设以为根的子树为

定义为以下结点的 DFN 的最小值(与 Tarjan 有向图中的区分):

  1. 中的结点;
  2. 通过一条不在搜索树上的边能到达的结点。

不难发现,按 DFS 生成树的递归遍历顺序是单调递增的,因此可以在回溯的过程中求出

无向图的割点与割边

割点:对于无向图中的结点,如果删掉它以及与它相连的边后,整个图连通块数量增加,则结点被称为无向图的割点。

割边:对于无向图中的边,如果删掉它后,整个图连通块数量增加,则被称为无向图的割边,也称作桥。

cca-3

判定割边

判定割边的条件:

  1. 是 DFS 树上的边。
  2. 的父结点,则满足。也就是说,从出发,不经过的前提下无法走到更早访问的结点,则作为与图的唯一连接,即为割边。
int dfn[N],low[N],dfn_cnt;
int ans[N],cnt;
void tarjan(int k,int p){ //tarjan 找桥,根结点的父节点为 0
	dfn[k]=low[k]=++dfn_cnt;
	for(int i=h[k]; i; i=e[i].nex){
        int u=e[i].t;
		if(!dfn[u]){
            tarjan(u,k);
			low[k]=min(low[k],low[u]);
			if(dfn[k]<low[u])ans[++cnt]=e[i].idx;// 桥
		} else if(u!=p) low[k]=min(low[k],dfn[u]);
	}
}

判定割点

判定割点的条件:

  1. 不为根结点,则要求,存在的子结点,满足。 即中的结点最多能走到结点,那么将删除就会导致不连通。
  2. 是根结点,则要求存在至少 2 个的子结点,满足
int dfn[N],low[N],totdfn;
bool cut[N];
int ans[N],la;
void tarjan(int u,int p){
    dfn[u]=low[u]=++totdfn;
    int cnt=0;
    for(int i=h[u];i;i=e[i].nex){
        const int v=e[i].t;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            cnt+=dfn[u]<=low[v];
        }else low[u]=min(low[u],dfn[v]);
    }
    if(cnt-(p==0)>=1)cut[u]=1;
}

无向图的双连通分量

cca-4

边双连通分量

对于无向图,若其子图内不存在割边,则称边双连通分量

对于图,直接删掉所有割边,剩下分量的就是边双连通分量。

将边双连通分量缩点,就得到了的边双树。

点双连通分量

无向图的子图内不存在割点,则称是图点双连通分量

对于图,割点可能同时属于多个点双连通分量,但每一条边一定只属于一个点双连通分量。

图中通过边的不同颜色来标记点双连通分量。

求点双连通分量,需在 Tarjan 算法中维护一个栈:

  • 当结点被第一次访问时,把该结点入栈。
  • 当割点判定条件成立时,无论是否为根:
    • 从栈顶不断弹出结点,直到被弹出。
    • 刚才弹出的所有结点与结点一起构成一个点双连通分量。

点双连通分量与圆方树有密切联系。