【算法】Tarjan算法求強連通分量
阿新 • • 發佈:2018-10-28
標記 我們 else if show tar ans stk oid 入棧
概念:
- 在有向圖G中,如果兩個定點u可以到達v,並且v也可以到達u,那麽我們稱這兩個定點強連通。
- 如果有向圖G的任意兩個頂點都是強連通的,那麽我們稱G是一個強連通圖。
- 一個有向圖中的最大強連通子圖,稱為強連通分量。
tarjan的主要思想:
從一個點開始DFS,記錄兩個數組,dfn[]和low[]。
其中,dfn[i]指的是到達第i個點的時間。
low[i]指第i個點直接或間接可到達的點中的最小dfn[j]。
low[i]數組的初始值為dfn[i]。
舉個例子,如圖所示:
假如我們從第一個點開始跑DFS,dfn[1]=1,low[1]=1;那麽走到第2個點時,標記dfn[2]=2;第三個點dfn[3]=2;dfn[4]=3;dfn[5]=3;dfn[6]=4;
同時,我們也可以得到另一個數組low[]:
low[1]=1;low[2]=1;low[3]=1;low[4]=1;low[5]=3;low[6]=4;
推廣:
對於每一個沒有被遍歷到的點u,如果從當前點有一條到未遍歷點u的有向邊,則遍歷到u,同時將點u入棧,時間戳+1並用dfn[u]記錄到達點u的時間,枚舉從u發出的每一條邊,如果該邊指向的點沒有被訪問過,那麽繼續dfs,回溯後low[u]=min(low[u],low[v])(其中v為u可以到達的點。)如果該點已經訪問過並且該點仍在棧裏,那麽low[u]=min(low[u],dfn[v])。
證明:
略,作為一名OIer,知道結論就行了!!!
代碼:
void tarjan(int u) { low[u]=dfn[u]=++tim; instack[u]=1;stk[top++]=u; for(int i=H[u];i;i=X[i]) { int v=P[i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { cnt++; int k; do { siz[cnt]++; k=stk[--top]; belong[k]=cnt; instack[k]=0; } while(k!=u); } }
例題:
迷宮城堡
Summer Holiday
Instantaneous Transference
寶藏
【算法】Tarjan算法求強連通分量