(待完成)qbxt2019.05 总结11 - Tarjan缩点

求有向图的所有强连通分量:Tarjan

我们定义DFN[x]为搜索到x时的时间戳(即搜索到的时间)。LOW[x]为搜索树中x以及它的还未构成极大强连通分量的出点可以访问到的最早祖先的时间戳。有LOW[x]=min(DFN[x],DFN[j],LOW[k]),其中存在边(x,j),(x,k),j为x的祖先,k为x的子孙。

令v[i]表示i是否在当前dfs的栈中,若不在则v[i]=0,否则v[i]=1。

  1. 如果出点是自己的祖先,则拿祖先的DFN值来更新

  2. 如果出点不是自己的祖先,且没有自己构成一个强联通分量,则可以拿这个值得LOW值来更新。

直到LOW=DFN 找到了一个极大强连通分量

①找到一个未被搜索过的节点u,若不存在,退出,否则以这个节点为根开始建立搜索树。

②给该节点建立时间戳,将x压入栈中,枚举该节点的所有儿子x,若其儿子没被访问过,则搜索其儿子(重复②),之后更新LOW[u]=min(LOW[u],LOW[x]),否则若v[x]=1(表示x是u的祖先),则更新LOW[u]=min(LOW[u],DFN[x])。

③对u搜索完毕后,若LOW[u]=DFN[u],则找到了一个极大强连通分量,栈顶到u都为一个极大强连通分量。更新v与栈。

void dfs(int k)
{
  DFN[k]=LOW[k]=++Time; v[k]=true; st[++r]=k; int R=r;
  for (int i=k的所有连向的点)
  {
     if (!DFN[i]) {dfs(i); LOW[k]=min(LOW[k],LOW[i]);} else 
     if (v[i]) LOW[k]=min(LOW[k],DFN[i]);
  }
  if (LOW[k]==DFN[k]) {for (int i=R; i<=r; i++) {…} r=R-1;}
}

猜你喜欢

转载自www.cnblogs.com/water-lift/p/10810005.html