1. 程式人生 > >(待完成)qbxt2019.05 總結11 - Tarjan縮點

(待完成)qbxt2019.05 總結11 - Tarjan縮點

搜索 節點 一個 不存在 code 當前 連通 總結 強聯通

求有向圖的所有強連通分量: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;}
}

(待完成)qbxt2019.05 總結11 - Tarjan縮點