上节
这次我们来讲一讲 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)
好了,强连通分量系列就要结束了,你觉得怎么样呢?投个票吧~
对了,光学不练可不行呐,我会给大家整理一些题目,我也会去写题解,链接会在讨论区。
那么,下次见!
参考资料: