连通性+ 1

早在普及组的时候,我们就学会了:

  • DFS(BFS)搜连通块

  • 并查集在加边的情况下动态维护连通块(支持离线处理删边)

现在,我问你:

  • 我删去一个点/边,判断剩下的图存在原本某两个连通的点现在不连通?

  • 我随机删去一条边,判断剩下的图中某两个点是否一定连通?

  • 我随机给你一些点,判断其中两两是否互相可达(有向图上)?

第三个问题不是今天这篇文章所讲的范畴,但是其他问题确实可以讲一讲。

我删去一个点/边,判断剩下的图存在原本某两个连通的点现在不连通?

形式化定义:有 \(G = (V, E), d \in V\),判断:

\(\exists x, y, x \ne d \land y \ne d \land (\exists v = (v_1, v_2, \cdots, v_k), v_1 = x \land v_k =y \land (\forall 1 \le i < k, (v_i, v_{i + 1}) \in E)) \land (\nexists v = (v_1, v_2, \cdots, v_k), v_1 = x \land v_k =y \land (\forall 1 \le i < k, (v_i, v_{i + 1}) \in E) \land (\forall 1 \le i \le k, v_i \ne d))\),如果成立则称 \(d\) 为割点。

这个问题可以使用 Tarjan 求解。

Tarjan(谐音太监,虽然其正确中文名为塔杨)通过两个数组来求解:\(dfn_i\) 表示 \(i\) 的 DFS 序,\(low_i\) 表示在不经过 \(i\) 在 DFS 树上的父亲所能走到的 \(dfn\) 最小的节点。

如果对于 \(u\) 有一个 \(u\) 的儿子 \(v\) 满足 \(low_v \ge dfn_u\),也就是不能回到祖先,那么就可以确定 \(u\) 是割点了...吗?

根节点的每一个儿子必然满足条件,所以我们要特判:

根是割点当且仅当根在树上有至少两个儿子。

伪代码:

function() Tarjan(x, fa, rt) does
  (int)c(0)
  dfn[x] = low[x] = ++cnt, vis[x] = 1
  for(each i \in adj[x]) does
    when(!vis[i]) then
      c++
      Tarjan(i, x, rt)
      low[x] sets(\min) low[i]
      when(x \ne rt \and low[i] \ge dfn[x]) then
        satis[x] = 1
      back on track
    and when(i \ne fa) then
      low[x] sets(\min) dfn[i]
    back on track
  back on track
  when(x \eq rt \and c \gt 1) then
    satis[x] = 1
  back on track
back on track

形式化定义:有 \(G = (V, E), d \in E\),判断:

\(\exists x, y, (\exists v = (v_1, v_2, \cdots, v_k), v_1 = x \land v_k =y \land (\forall 1 \le i < k, (v_i, v_{i + 1}) \in E)) \land (\nexists v = (v_1, v_2, \cdots, v_k), v_1 = x \land v_k =y \land (\forall 1 \le i < k, (v_i, v_{i + 1}) \in E \backslash \{d\}))\)

跟点的情况很像,具体看伪代码:

function() Tarjan(x, fa) does
  dfn[x] = low[x] = ++cnt, vis[x] = 1
  for(each i \in adj[x]) does
    when(!vis[i]) then
      Tarjan(i, x, rt)
      low[x] sets(\min) low[i]
      (note)(没有根的特殊情况)
      when(low[i] \ge dfn[x]) then
        satis[i] = 1 (note)(实际上是孩子)
      back on track
    and when(i \ne fa) then
      low[x] sets(\min) dfn[i]
    back on track
  back on track
  (note)(没有根的特殊情况)
back on track

我随机删去一条边,判断剩下的图中某两个点是否一定连通?

很简单:

按照上面的方式处理出桥,断掉桥,条件满足当且仅当之后的图中两个点仍然连通。

附录:Tarjan 模板

function() Tarjan(x, fa) does
  dfn[x] = low[x] = ++cnt, vis[x] = 1
  for(each i \in adj[x]) does
    when(!vis[i]) then
      Tarjan(i, x)
      low[x] sets(\min) low[i]
    and when(i \ne fa) then
      low[x] sets(\min) dfn[i]
    back on track
  back on track
back on track
posted @ 2024-04-09 16:19  hhc0001  阅读(14)  评论(0编辑  收藏  举报