Tarjan算法

介绍

对任意有向图 G=(V,E) ,我们定义强连通关系 uv (这里 u,vV ),当且仅当存在 u v的路径以及 v u的路径。容易看到这是一个等价关系,因此可以将 V 划分成不相交的子集并,我们称每个子集为G的强连通分支。

Tarjan算法作用即是对任意有向图,求出其所有的强连通分支。且其时间复杂度为 O(|V|+|E|)

算法

Tarjan算法本身十分简洁,但它的思想却非常巧妙。我们接下来介绍算法的具体内容:

算法的主体部分为深度优先搜索,在搜索的过程中对每个顶点维护两个属性lowlink和index。这里index表示深度优先搜索的访问顺序编号,即第 n 个访问的顶点index=n。lowlink是算法的关键所在,它的意义是记录从当前顶点所能到达的顶点中index最小的顶点。

算法同时维护一个栈,这个栈是tarjan算法的重要不变量,即顶点在栈中当且仅当它的lowlink对应的顶点也在栈中。

具体算法参考:维基百科。其关键步骤是:

  1. 用DFS访问每个顶点。
  2. 当访问到顶点 v 时,将其压栈。其index值即为当前访问序号,其lowlink值递归定义如下(初始时v.lowlink=v.index):
    • (v,w)E w 还未访问,那么(递归)访问w,并且令 v.lowlink=min{v.lowlink,w.lowlink}
    • (v,w)E w 还留在栈中,那么说明其已被访问,此时令v.lowlink=min{v.lowlink,w.index}
  3. 若对于顶点 v ,(递归回来后)有v.lowlink=v.index。那么将栈pop到 v (包括v),这些pop出来的顶点即构成一个强连通分支。

正确性

我们只需证明下面的结论:

  • v.lowlink=v.index 时从 v 到栈顶的元素包含且只包含v所在强连通分支的所有元素。
  • 栈最终会清空(由于算法会最终会返回到出发顶点,这是显然的。)

证明:否则。若有某个 v 的连通分支所包含的顶点w未被访问过,那么存在从 v w的路径,由DFS的性质算法会继续搜索而不会返回。若有某个分支顶点 w v先访问,那么由于存在 v w的路径,因此这个递归分支返回的lowlink值必定不大于 w.index ,即 v.lowlinkw.index<v.index ,矛盾!最后,我们证明任何分支顶点 w ,不会在算法返回到v之前被pop掉,且任意非分支顶点都会pop掉。这是因为由强连通性存在 w v的路径,因此由前面的讨论我们有 w.lowlinkv.index<w.index ,这不满足pop的条件。而对于非分支点,其 lowlink 必定大于 v index(否则会使 v.lowlink 减小),因此在返回之前必定会pop掉。

同时由DFS的性质容易知道复杂度为 O(|V|+|E|)

类似算法

Tarjan算法的思想可以应用到很多问题上去,比如求解图的欧拉回路。我们可以给出算法如下:

  1. 用DFS访问所有边
  2. 若顶点 v 被访问,那么将其压栈。若此时v没有可访问的边,那么将其出栈。

容易知道若图存在欧拉回路,那么上面算法产生的序列即为一个回路。

另一个应用是求出无向图的无桥边连通分支(这个是直接应用)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值