tarjan算法以及一般的有向图强连通分量算法

强连通图:任意两点可以互达的有向图。

强连通分量:极大强连通子图。

白色路径定理:请自行百度(不是重点)

1.首先从一般的算法开始

一个有向图可以看成连通分量组成的有向无环图(但要注意,连通分量之间可能有多条边);

否则,不同连通分量将被连通。

可以看到,只要按逆拓扑序依次遍历连通分量,可以依次得到连通分量。

我们知道,利用深度优先搜索,按退出dfs的顺序可以得到有向无环图的逆拓扑序,但两者毕竟还是有区别的,很不凑巧,在连通分量组成的有向无环图中,最先退出dfs的可能不是出度为0的连通分量(可以先在自家绕一圈嘛)。

但是,最后退出dfs的顺序确实是逆拓扑序

严格证明需要用到白色路径定理(听起来高大上,其实很low,但真的很有用)

所以简单说明一下,假设先进行后继分量的搜索,那么等搜索完了也搜索不到前驱。

假设先进行前驱搜索(此时后继要么搜完了,要么没动,不可能正在搜),那么后继没搜完,前驱就不会退出。

因此,前驱比后继退出dfs要晚。

但是,但是,是最晚退出dfs的时间要晚,也就是说,对于所有顶点,只能保证最晚退出的是拓扑序的第一个,而不能保证最早退出的是逆拓扑序的最后一个。我们只能以拓扑序的顺序得到连通分量,这要求我们使用转置图(把所有边方向反转,连通分量不变),这样就变成转置图的逆拓扑序;

好了,思想相信你已经get了。具体做法就是,先dfs得到顶点退出时间,再从最晚顶点开始不断在转置图上“摘”连通量。

2.tarjan算法

结合深度优先搜索图看一下

 根据白色路径定理,分量上第一被发现的点,是同分量其他点的祖先。

但不排除后代没有其他连通分量。

所以我们要以一定顺序,把连通分量摘下来,使得每次连通分量不包含其他连通分量构成的子树。

根据前面的讨论,最晚节点退出dfs的顺序是一个逆拓扑序(即根节点/祖先退出的顺序),可以按这个顺序摘。

但现在我们从另一个角度来看,如果根结点退出dfs,那么子树也早就退出dfs,所以如果一个连通分量根节点不包含其他连通分量构成的子树,那么他最先退出dfs,因此我们可以通过退出dfs的顺序摘分量。

现在只要判断退出dfs的是不是根节点了

开动开动脑筋吧,下一个图灵奖得主。

好吧,你的脑子说你不想。

注意,在一棵连通分量子树中,对于一个节点(除根节点),自己或者其后代必然到祖先有直接的边,否则就不能和祖先互达(这里没有说根节点是因为可能仅到祖先有直接的边,再通过祖先与根节点连通)

若我们设置一个访问顺序数组dfn,和一个存储访问到的(不是有路可达的,见反例)最早点数组low。

若自己或者其后代必然到祖先有直接的边,再通过回溯,那么最早点数组里就是某个祖先的访问时间(根节点除外)。

这样,若low[i]==dfn[i],就能断定该点是根节点(你可能要问,根节点到其他分量有边怎么办,结合第一个图,分量只能到后继有边,后继在其根节点退出dfs已被摘除,根本无法回溯)。

具体做法,用栈存储搜索树,dfs的时候判断根节点,如果是的话,把树摘出来。

代码的话,去网上搜吧。

相关信息见《算法导论》第三版p357

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值