什么?都3202年了,你还不会强连通分量?(三)

上节


这次我们来讲一讲 Tarjan 算法的另外一种时现方式—— Garbow 算法

Tarjan 算法是用 dfn \text{dfn} dfn low \text{low} low 来计算强连通分量的根,Garbow 算法是维护一个节点栈,并用第二个栈来确定何时从第一个栈中弹出属于同一个强连通分量的节点。从节点 u u u 开始的 DFS \text{DFS} DFS 过程中,当一条路径显示这组节点都属于同一个强连通分量时,只要栈顶节点的访问时间大于根节点 u u u 的访问时间,就从第二个栈中弹出这个节点,那么最后只留下根节点 u u u。在这个过程中每一个被弹出的节点都属于同一个强连通分量。

当回溯到某一个节点 u u u 时,如果这个节点在第二个栈的顶部,就说明这个节点是强连通分量的起始节点,在这个节点之后搜索到的那些节点都属于同一个强连通分量,于是从第一个栈中弹出那些节点,构成强连通分量。

下面康康代码:

C++:

int garbow(int u) 
{
	stack1[++p1]=u;
	stack2[++p2]=u;
	low[u]=++dfs_clock;
	for (int i=head[u];i;i=e[i].next) 
	{
		int v=e[i].to;
		if (!low[v]) garbow(v);
		else if (!sccno[v]) while (low[stack2[p2]]>low[v]) p2--;
	}
	if (stack2[p2]==u) 
	{
		p2--;
		scc_cnt++;
		do 
		{
			sccno[stack1[p1]]=scc_cnt;
		} while (stack1[p1--]!=u);
	}
	return 0;
}

void find_scc(int n) 
{
	dfs_clock=scc_cnt=0;
	p1=p2=0;
	memset(sccno,0,sizeof(sccno));
	memset(low,0,sizeof(low));
	for (int i=1;i<=n;i++) if (!low[i]) garbow(i);
}

Python :

def garbow(u):
    stack1[p1] = u
    stack2[p2] = u
    p1 = p1 + 1; p2 = p2 + 1
    low[u] = dfs_clock
    dfs_clock = dfs_clock + 1
    i = head[u]
    while i:
        v = e[i].to
        if low[v] == False:
            garbow(v)
        elif sccno[v] == False:
            while low[stack2[p2]] > low[v]:
                p2 = p2 - 1
    if stack2[p2] == u:
        p2 = p2 - 1
        scc_cnt = scc_cnt + 1
        while stack1[p1] != u:
            p1 = p1 - 1
            sccno[stack1[p1]] = scc_cnt

def find_scc(n):
    dfs_clock = scc_cnt = 0
    p1 = p2 = 0
    sccno = []; low = []
    for i in range(1, n + 1):
        if low[i] == False:
            garbow(i)

好了,强连通分量系列就要结束了,你觉得怎么样呢?投个票吧~

对了,光学不练可不行呐,我会给大家整理一些题目,我也会去写题解,链接会在讨论区。

那么,下次见!


参考资料:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值