📜  双连通图(1)

📅  最后修改于: 2023-12-03 15:07:22.929000             🧑  作者: Mango

双连通图

什么是双连通图

在图论中,双连通图又称为重连通图或双重连通图,是指一个无向图任意两个顶点间至少存在两条不同的简单路径时,该图称为双连通图。如果一个无向图不是双连通图,则称为一个割点存在的图。

双连通图的性质

双连通图的一个性质是:任何一个割点都不会是一个双连通分量中的点。而且一个无向图是双连通图当且仅当它没有割点。这个性质可以通过 DFS 来证明,如果有一棵 DFS 树的一个点 u 子树上有 v 是 u 的祖先,如果删掉 u 后 v 还在同一个连通块中,那么 u 就是割点。

另外,如果一个点在一个双连通分量里,那么它跟它的祖先、子孙之间都存在可达路径。

如何找到双连通分量
Tarjan 算法

Tarjan 算法是一种常见的求解双连通分量的方法。算法流程如下:

  1. 对每个节点 v,记录它的 DFS 树的深度 DFN[v] 和能回到的最小深度 LOW[v];
  2. 当从节点 v 的子节点子树中有一条边指向了 v 的祖先时,更新 v 的 LOW 值;
  3. 如果当前节点是根节点,且有两个或以上的子节点,则该根节点是一个双连通分量的根;
  4. 当访问完一个节点子树后,如果 v 的 LOW 值不小于 DFN[v],表明不存在从 v 或 v 的任意子节点出发的回溯边,即当前节点 v 是一个双连通分量的一个成员。

下面是一段求解双连通分量的 Tarjan 算法的 Python 代码(时间复杂度为 O(V + E)):

graph = [[] for _ in range(n)]  # 储存图的数据结构
dfn = [0] * n  # DFN 数组
low = [0] * n  # LOW 值
vis = [False] * n # 判断节点是否被访问过
stk = []  # 栈
biconnected_comps = []  # 双连通分量列表

def tarjan(u, p):
    global clock
    dfn[u] = low[u] = clock
    vis[u] = True
    child_cnt = 0  # 子节点个数
    for v in graph[u]:
        if not vis[v]:
            stk.append((u, v))
            child_cnt += 1
            clock += 1
            tarjan(v, u)
            low[u] = min(low[u], low[v])
            if low[v] >= dfn[u]:
                subg = [(u, v)]
                while subg[-1] != (u, v):
                    subg.append(stk.pop())
                biconnected_comps.append(subg)
        elif v != p and dfn[v] < dfn[u]:  # 处理回溯边
            stk.append((u, v))
            low[u] = min(low[u], dfn[v])
    if p is None and child_cnt >= 2:  # 处理根节点成为双连通分量的情况
        subg = [(u, v) for u, v in stk if u == stk[-1][0]]
        biconnected_comps.append(subg)
    clock += 1

clock = 0
for i in range(n):
    if not vis[i]:
        tarjan(i, None)

总结

双连通图是图论中的一个重要概念,它在许多场合都有应用,如网络通信、数据挖掘、图像处理等。Tarjan 算法是求解双连通分量的一种有效方法,在实际应用中具有广泛的使用价值。