tarjan

理解 tarjan 和缩点

写了个证明在知乎:Tarjan scc 证明

tarjan 求强连通分量

理解这个过程的关键在于以 dfs 搜索树和搜索栈的视角来看待图遍历

众所周知 dfs 一个图的过程可以看作一棵树


  • 问:如果树的一个节点 可以延申一条边到 的祖先,说明什么
  • 答:说明 位于同一个强连通分量

  • 问:如果 不是 的祖先,说明什么
  • 答:看情况, 能连 说明 在同一个强连通分量,而 能连 什么也说明不了

  • 问:是什么造成了这种差异
  • 答:因为 强连通, 的祖先

  • 问:强连通说明什么
  • 答: 强连通,从某种意义上可以将 看作同一个点

  • 问:然后呢
  • 答:所以 实际上可以看作就是 的祖先

  • 问:有个问题,如果 dfs 的过程中,先发现 能连接 ,然后才发现 能连 ,可怎么办
  • 答:这种情况不会出现

  • 问:为什么
  • 答:因为如果 在同一个强连通分量,那么当 还在搜索栈里的时候,一定有办法碰到

  • 问:也就是说不可能出现 没发现 跟自己在同一个强连通分量里,反而要通过后续的 来间接发现的情况
  • 答:对

  • 问:所以当看到 能碰到 的时候直接无视就好了
  • 答:对。因为如果 能碰到 ,但 又不在 的子树里,这说明 已经遍历完了。 这也说明 不在 的子树里。所以假如 能与 强连通,那么唯一的可能是他们都至少与 强连通, 是他们的公共祖先

  • 问:所以即使 强连通,他们也有可能不在对方的子树里
  • 答:对。可以想象这样一种情况: 强连通,但他们之间仅仅由一个节点 连接,没有其他互相到达的路径。如果此时 dfs 不巧以 作为二者的祖先来遍历,那么由于每个节点都只在 dfs 中出现一次, 不能通过 来互相抵达

  • 问:是搜索剪枝导致它这样的
  • 答:是的

  • 问:那假如 强连通,则他们一定都与 强连通吗?我的意思是,他们有没有可能通过其他节点来连接起来
  • 答:可以分情况解答:
    1. 和他们其他的公共祖先,比如 强连通,那么 一定和 也强连通,这很显然
    2. 通过 强连通起来,那么在 dfs 的过程里, 应该是 的公共祖先,这与现在的情况矛盾

  • 问:我再想想 #沉淀
  • 答:如果从结果倒推,当 dfs 接触到一坨强连通分量时,碰到的第一个节点 就应该是该强连通分量里其他所有节点的祖先。这很自然,因为从 一定能到达其余所有节点


  • 问:也就是说,从直观上来看,一个强连通分量在 dfs 树上一定也是连通的
  • 答:是的,只要 dfs 搜索树长成了这样,并且 不连通,那么就算 连出了花,他们也一定不连通

  • 问:因为如果 连通,那么他们一定都和 连通。同样如果 连通,则他们要么一方在另一方的子树里,要么有连通的公共祖先
  • 答:对

  • 问:是不是如果 在不同的子树,但他们连通,则他们一定有且仅有唯一的公共祖先
  • 答:并不,比如他们可以和最小公共祖先的父节点也连通