图论相关:Tarjan

关于 Tarjan 求强连通分量 搜了几个帖子,虽然已经讲的很详细了,但是还得自己琢磨一下,于是消化后做个笔记。

参考链接:
1. 休伯利安矿工
2. 我。。。我是谁?

几个基本概念

  • 连通:无向图中,从任意点i可以到达任意点j;
  • 强连通:有向图中,从任意点i可以到达任意点j;
    弱联通:把有向图看成无向图,从任意点i可以到达任意点j; 在有向图中成为强连通分量的条件较为苛刻 所以引入强连通分量这个概念
    强连通分量:局部区域强连通

Tarjan 求强连通分量

几个计算强连通分量的时候会用到的工具:

  • vector邻接表(存图)
  • 栈 st(用来存放属于同一个强连通分量的节点)
  • time (节点被访问的顺序)
  • dfn数组(存储节点被访问的顺序)
  • low数组 (可以到达的最早的时间点)
  • bool 型的instake数组 (标记节点是否在栈里)
  • 每一个节点都有两个属性,表示为(a,b):a 为该节点被真正访问到的顺序,b为可以最快访问到该节点的时间戳;例如编号为 i 的节点,其两个属性可以标识为 a = dfn[i] , b = low[i]。 a 很好理解,就是遍历过程中,节点 i 被访问到的次序,而节点 i 的 b值稍稍绕一点,它的取值方法为:1. 找到节点 i 可以通往的(有向的)所有其他节点(也包括自身);2. 从这些节点属性中的low 值(也就是b)中取一个最小值作为节点 i 的b值。

以下面这个图的联通区域查找过程为例
在这里插入图片描述

算法步骤:

  1. 从节点1开始正向搜索,一直搜索到节点6,搜索过程中每搜索一步,就把当前节点压入栈中(即对 dfn[i] 赋值),同时对当前节点的 low[i] 初始化,取值为 low[i] = dfn[i] 。注意两点:(1)节点3有两个邻接节点,算法中可以任意取一条;(2)正向搜索停止得条件是:a. 当前节点没有邻接节点; b. 当前节点有邻接节点,但是该节点已经在栈里面出现过了。
  2. 停止搜索后,开始回溯,从停止节点开始。回溯方法是:(1)更新停止的节点的 low[i] 值,更新方法是首先找到节点 i 可以通往的(有向的)所有其他节点(也包括自身),然后从这些节点属性中的low 值中取一个最小值作为节点 i 的low[i] 值;(2)判断节点 i 的 dfn值 与 low 值是否相同,如果相同,则将该节点标加为一个强连通分量,并将该节点出栈,且从图中删除,删除后,沿着栈的顺序回退一步;如果不同,直接根据栈中节点的顺序回退一步(注意回退的时候节点不出栈),然后重复步骤(1)(2)。如果回退过程中发现有未访问过的通路,则停止回溯,继续正向搜索,正向搜索到头了,再继续回溯…

具体步骤细节:

  • 第一次正向搜索到节点6,回溯结果是:将节点5、6 标记为两个 强连通分量,并出栈。搜索位置回到节点3,并向节点4开始正向搜索;
    图1

  • 搜索到节点4的时候,发现它的邻接节点(节点1)已经在栈中,处于锁定状态,因此搜索到节点4就停止了,开始回溯,节点4的low值应取节点1和节点4的low值得最小值即 low[4] = min( low[1], low[4] ) 注:初次搜索到节点4时,会用搜索次序初始化它的low值,因为节点4是第5个访问的节点,所以初始化为 5。
    在这里插入图片描述

  • 回溯完节点4,继续回溯到节点3,同样的,节点3的通路(节点4)在栈中,基于同样的原因,节点3的low值也被更新为了1
    在这里插入图片描述

  • 最后回到了节点1,由于节点1还有邻接节点未被访问,因此不更新它的low值,直接访问到节点2
    在这里插入图片描述

  • 节点2的有一个通路处于阻塞状态,然后开始执行回溯的两个步骤——更新low值和回退,结果就是节点2的low值也是1。
    在这里插入图片描述

  • 最后,low值相同的为一组连通分量,结果就就是,该图总共有3个连通分量, {1 2 3 4}、{5}、{6}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值