1. 程式人生 > 其它 >【Tarjan求強連通分量】【模板】

【Tarjan求強連通分量】【模板】

分析

  1. 首先可以採用dfs的方式,對每個點遍歷一遍,若其尚未訪問,則以它為起點dfs,那麼此次dfs中未遍歷到的點一定不可能與遍歷到的點形成強連通分量,因為強連通分量要求能夠互相到達。
  2. 在一次dfs中,每個scc一定存在一個節點是這個scc中其他所有點的祖先節點。證明:否則,這個scc可以劃分為若干棵樹,這些樹之間只能以橫叉邊相連,而橫叉邊只能從dfn序大的指向小的,而強連通分量要求相互到達,且其中任意兩棵樹一定滿足其中的一棵樹的所有節點的dfn序一定大於另一顆樹的所有節點的dfn序,那麼這就會形成矛盾。
  3. 我們考慮維護一個棧,儲存所有能夠到達當前節點x的節點。那麼棧中一定包括所有x的祖先節點,還有通過反向邊可以到達x的祖先節點的點。定義low[x]為x能通過最多一條非樹邊到達的dfn序最小的在棧中的節點。那麼當回溯時若有dfn[x]==low[x]則可判定從棧頂到x的所有節點構成一個scc
  4. 訪問到一個新節點x時,把x壓進棧,dfn[x]=low[x]=++tot.
  5. 對於x連向的每個節點y:若y尚未訪問過,則(x,y)是樹枝邊,先dfs(y),用lowy更新lowx(這裡其實有兩種情況,見Tip);若y被訪問過,且y在棧中,用dfny更新lowx
  6. 回溯時若有若有dfn[x]==low[x],則可一直彈棧直到x出棧,彈出的所有節點構成一個scc
  7. 縮點時列舉每條邊,若兩端點分屬不同scc,則加入新DAG中。
    Tip:若lowy可以到達x,那麼滿足條件,可以更新lowx。如果lowy不可以到達x,那麼lowy一定等於y,大於dfnx,一定不會對lowx造成影響。

Code