Tarjan算法思路剖析

强连通分量就是有向图的极大子图

通过Tarjan算法把一个图分成多个强连通分量形成DAG,从而会具有一些很好的性质

Tarjan本质上还是递归操作,在递归的时候同时维护两个时间戳数组

其中dfn数组维护的是第一次遍历到的序号:有vis数组的作用,还有判断此点是不是这个点属于的连通分量中的根节点的作用

另外一个数组就是low数组,low[u]表示从u的子树中的结点出发,走一条交叉后向边或者边可以到达的v的dfs的最小值,并且要求v还能到达u(等价于v在栈中)

我们刚开始选到一个点u,先将其压入栈中,并且将其dfs和low中的值都赋为当前维护的计数值(每次先++),然后就开始深搜,若是深搜到的点还没有被遍历过(也就是dfn数组为0),那么就顺着这点搜下去,然后递归来更新u的low值。若是这个点更新过,而且被标记在栈中,那么直接用这个点的dfn值来更新u的low值

在遍历的时候,若是做完这个点的dfs操作后发现dfn数组和low数组中的值相同,那么就将其当做一个连通分量中的根节点并开始用栈往外弹在同一个连通分量中的所有的点(要用一个数组模拟栈,就因为从根节点开始往栈中压元素,根节点自然是在栈底的,那么根节点以及在根节点上方的元素自然同属于一个连通分量)

所以我们还需要一个数组来装同一个连通分量中的所有元素,同时还需要用到一个do-while循环来弹出同一个连通分量中的所有元素

tarjan模板呈上

void tarjan(int u)
{
	dfn[u] = low[u] = ++timestamp;
	stk[++top] = u,in_stk[u] = 1;
	for(int i=h[u];~i;i=ne[i])
	{
		int j = e[i];
		if(!dfn[j]) 
		{
			tarjan(j);
			low[u] = min(low[u],low[j]);
		}
		else if(in_stk[j]) low[u] = min(low[u],dfn[j]);
	}
	
	if(dfn[u]==low[u])         //往栈里存元素+出栈 
	{
		++scc_cnt;
		int y;
		do
		{
			y = stk[top--];    //出栈  
			in_stk[y] = 0;     //标记点 
			id[y] = scc_cnt;
			s[scc_cnt]++;      //记录栈中元素个数 
		}while(y!=u);
	}
}

要加油啊~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值