Tarjan求强连通分量

Tarjan的实质是将一个有向图的一些环(即强连通分量)浓缩成一个个结点,并且将环上所有点权都累积到当前浓缩后的点上。这有什么用?在出现正权回路spfa刷不了时,能将一个正权回路缩成点,避免了环上的点循环入队。那么Tarjan又是怎样工作的呢?当然,它一般是通过DFS来实现的。我们用clk记录时间结点(时间戳,即每访问一个点,clk+1)。接着,我们用dfn[x]表示访问结点x的时间戳(这个值是一直恒定的),用low[x]表示x能追溯到的最远的祖先(dfn[fa[x]]尽可能的小)。最初刚访问到这个点时,我们什么信息也不清楚,所以使low[x]=dfn[x]=++clk;除此之外,我们还要设立一个栈,用以存放环上的结点。所以还要将它入栈,并将instk[x]变为1。即已在栈内。那么,接着,我们用邻接表来处理与他相邻的点。那么,设当前结点为x,下一结点(son结点)为son[j],将会出现三种情况:

1.(dfn[son[j]]&&!Instk[son[j]]),这表示当前结点已经访问过了,但是它在这先前就出栈了。这意为着什么?就意味着他已经与其他结点已经构成环或自环了(构成环后就要把这个环上的元素从栈中删去)。所以,此时,son[j]与x已经没有联系了,已经”用不到“了。

2.(dfn[son[j]]&&Instk[son[j]]),这表示当前结点已经访问过,而且”正在形成“环,就是说这即将形成,但还没有构成完整的环。那么,此时,low[x]=min(low[x],dfn[son[j]]),就是说x,son[j]肯定是在一个强连通里面的。

3.(!dfn[son[j]]&&!Instk[son[j]]),当结点son[j]还未访问过时,它不可能会在栈里。此时递归调用tarjan(son[j])。接着,我们知道了low[son[j]]的值,所以我们要跟新low[x]的值,low[x]=min(low[x],low[son[x]]);这相当于一个迭代的过程,层层递归返回得到了low[x]的新值。

那么,如何判断形成了环呢?当(low[x]==dfn[x])的时候最后的时候,说明能追溯它自己,也就是说这是一个环。就把这个环上(有可能是自环)的元素的权值都给成祖先x(缩成一个点)。(即一直删除栈顶元素,直到栈顶元素==祖先x,祖先x也要一同删去)接着就可以按照题目的意思运用了,比如重新造边,然后再做最短路。那么在Tarja过程中还可以查询有几个强连通,以及每个强连通的大小,能根据题目意思运用就行。

转载于:https://www.cnblogs.com/whc200305/p/7112970.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值