Tarjan算法

Tarjan算法是一种用于寻找有向图中强连通分量的深度优先搜索算法。通过时间戳dfn和low值来判断节点是否属于同一个强连通分量,最终找到最大强联通分量。算法流程包括初始化时间戳,进行DFS搜索,并根据low值更新节点信息,找出强连通分量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。

Tarjan算法可以用于求一张有向图的最大强联通分量

基本参数

对于一张有向图

这里写图片描述

上图来自byvoid大牛
进行dfs搜索后会出现一棵dfs搜索树

这里写图片描述

1.time表示时间戳,表示这个节点是第几个被访问的
2.dfn表示u节点的时间戳
low数组表示以u为根节点的子树中的节点能访问到的时间戳最小的节点的时间戳
开始时low[u]=dfn[u]
搜索完u所有相邻的节点后
low[u]=min(low[u],low[v])(u能访问v且v不在其他强连通分量中)
例如
low[1]=1
low[2]=1
low[4]=1

算法流程

tarjan(u)
{
DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
for each (u, v) in E // 枚举每一条边
if (v is not visted) // 如果节点v未被访问过
tarjan(v) // 继续向下找
Low[u] = min(Low[u], Low[v])
else if (v in S) // 如果节点v还在栈内
Low[u] = min(Low[u], DFN[v])
if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
repeat
v = S.pop // 将v退栈,为该强连通分量中一个顶点
print v
until (u== v)
}

转自byvoid大牛

代码:

const
  maxn=100;
var
  n,m,i,c,d,time,top:longint;
  relation:array[0..maxn,0..maxn] of boolean;
  dfn,low,stack:array[0..maxn] of longint;
  visit,instack:array[0..maxn] of boolean;
  function min(a,b:longint):longint;
begin
  if a<b
  then min:=a
  else min:=b;
end;
  procedure tarjan(u:longint);
var
  i:longint;
begin
  inc(time);
  low[u]:=time;
  dfn[u]:=time;
  visit[u]:=true;
  inc(top);
  stack[top]:=u;
  instack[u]:=true;
  for i:=1 to n do
    begin
      if relation[u,i]
      then begin
             if visit[i]=false
             then begin
                    tarjan(i);
                    low[u]:=min(low[u],low[i]);
                  end
             else if instack[i]
                  then low[u]:=min(low[u],low[i]);
           end;
    end;
   if low[u]=dfn[u]
   then begin
          while (top>0) and (stack[top]<>u) do
            begin
              write(stack[top],' ');
              instack[stack[top]]:=false;
              dec(top);
            end;
          write(stack[top]);
          instack[stack[top]]:=false;
          dec(top);
          writeln;
        end;
end;

begin
  read(n,m);
  fillchar(relation,sizeof(relation),false);
  for i:=1 to m do
    begin
      read(c,d);
      relation[c,d]:=true;
    end;
  time:=0;
  top:=0;
  fillchar(dfn,sizeof(dfn),0);
  fillchar(low,sizeof(low),0);
  fillchar(visit,sizeof(visit),false);
  fillchar(instack,sizeof(instack),false);
  tarjan(1);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值