tarjan求強連通分量
割點總體思想:遍歷每乙個結點並使用並查集記錄父子關係。
tarjan 是一種dfs的思想。我們需要從根結點去遍歷這棵樹。
當遍歷到某乙個結點(稱之為 x
xx) 時,你有以下幾點需要做的。
將當前結點標記為已經訪問。
遞迴遍歷所有它的子節點(稱之為 y
yy),並在遞迴執行完後用並查集合並 x
xx 和 yyy。
遍歷與當前節點有查詢關係的結點(稱之為 z)(即是需要查詢 lca 的另一些結點),如果 z
zz 已經訪問,那麼 x
xx 與 z
zz 的 lca
lcalc
a 就是 get
fa(z
)getfa(z)
getfa(
z)(這個是並查集中的查詢函式),輸出或者記錄下來就可以了。
這是偽**
void tarjan(int x)
for (i=1;i<=有查詢關係的結點數;i++)edge[500001],ed[500001];
void add(int from,int to)
void tarjan(int now)
else if(!co[to])
}if(low[now]==dfn[now])
--top;
}}int topo()
while(!q.empty())
}int maxn=0;
for(int i=1;i<=col;i++)
return maxn;
}int main()
for(int i=1;i<=m;i++)
top=0;
for(int i=1;i<=n;i++)
for(int i=1;i<=m;i++)
}cout《可以使用tarjan演算法求割點(注意,還有乙個求連通分量的演算法也叫tarjan演算法,與此演算法類似)。(tarjan,全名robert tarjan,美國計算機科學家。)
首先選定乙個根節點,從該根節點開始遍歷整個圖(使用dfs)。
對於根節點,判斷是不是割點很簡單——計算其子樹數量,如果有2棵即以上的子樹,就是割點。因為如果去掉這個點,這兩棵子樹就不能互相到達。
對於非根節點,判斷是不是割點就有些麻煩了。我們維護兩個陣列dfn和low,dfn[u]表示頂點u第幾個被(首次)訪問,low[u]表示頂點u及其子樹中的點,通過非父子邊(回邊),能夠回溯到的最早的點(dfn最小)的dfn值(但不能通過連線u與其父節點的邊)。對於邊(u, v),如果low[v]>=dfn[u],此時u就是割點。
但這裡也出現乙個問題:怎麼計算low[u]。
假設當前頂點為u,則預設low[u]=dfn[u],即最早只能回溯到自身。
有一條邊(u, v),如果v未訪問過,繼續dfs,dfs完之後,low[u]=min(low[u], low[v]);
如果v訪問過(且u不是v的父親),就不需要繼續dfs了,一定有dfn[v]#include#includeusing namespace std;
int read()
const int n=20005,m=100005;
int head[n],top=0;
struct nodeedge[m<<1];
void add(int u,int v)
int n,m,cnt,dfn[n],low[n],vis[n],tot=0,ans[n],num;
void dfs(int u,int rt)
} else low[u]=min(low[u],dfn[v]); }}
int cmp(int aa,int bb)
} }sort(ans+1,ans+num+1,cmp);
printf("%d\n",num);
for(int i=1;i<=num;i++)
return 0;
}
tarjan複習小結
雖然是複習,但還是學到許多。過程中遇到四種邊 1 樹枝邊 dfs 搜尋樹上的邊 滿足邊 u,v v 不在棧中 u 為 v 的父節點 2 前向邊 與 dfs 方向一致 祖先指向子孫 沒什麼用 3 後向邊 與 dfs 方向相反 子孫指向祖先 滿足邊 u,v v 在棧中,u 為 v 的祖先節點 4 橫叉邊...
Tarjan 複習小結
一 割點。void tarjan r i,r rt else low i min low i dfn to k if i rt sum 1 ans i 1 注意 在不聯通圖中,應當 for r i 1 i n i if dfn i tarjan i,i 這樣才能保證全部求到,注意根節點.二 橋。vo...
Tarjan專題總結複習
dfn x x 第一次被訪問的時間順序 時間戳 搜尋樹 每個節點只訪問一次,所有訪問過的邊 x,y 構成一棵搜尋樹 low x 定義為以下節點的時間戳的最小值 1.subtree x 中的節點。2.通過 1 條不在搜尋樹上的邊,能夠到達 subtree x 的節點。void tarjan int x...