標籤:log tarjan演算法 oid cto 節點 int 演算法 clear for
轉自:https://www.zhihu.com/question/40746887/answer/88428236
連通分量有三種∶邊雙連通分量,點雙連通分量,強連通分量,前兩種屬於無向圖,後一種屬於有向圖
定義:
雙連通分量又分雙連通分量和邊雙連通分量兩種。若一個無向圖中的去掉任意一個節點(一條邊)都不會改變此圖的連通性,即不存在割點(橋),則稱作點(邊)雙連通圖。一個無向圖中的每一個極大點(邊)雙連通子圖稱作此無向圖的點(邊)雙連通分量。
代碼如下:
點雙聯通struct Edge{ int u,v; Edge(int _u,int _v):u(_u),v(_v){}}edge[maxn];int dfn[maxn],low[maxn],cut[maxn],bccno[maxn];vector<int>gra[maxn],bcc[maxn];stack<int>stk;int cnt,bcnt;void tarjan(int f,int u){ dfn[u]=low[u]=++cnt; int child=0; int sz=gra[u].size(); for(int i=0;i<sz;i++){ int id=gra[u][i]; int v=edge[id].v; if(!dfn[v]){ stk.push(id); child++; tarjan(u,v); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){ cut[u]=1; bcc[++bcnt].clear(); while(1){ int id=stk.top(); stk.pop(); int uu=edge[id].u; int vv=edge[id].v; if(bccno[uu]!=bcnt){ bcc[bcnt].push_back(uu); bccno[uu]=bcnt; } if(bccno[vv]!=bcnt){ bcc[bcnt].push_back(vv); bccno[vv]=bcnt; } if(uu==u&&vv==v){ break; } } } }else if(dfn[v]<dfn[u]&&v!=f){ stk.push(id); low[u]=min(low[u],dfn[v]); } } if(f<0&&child==1){ cut[u]=0; }}邊雙聯通struct Edge{ int u,v; Edge(int _u,int _v):u(_u),v(_v){}}edge[maxn];int dfn[maxn],low[maxn],bccno[maxn];vector<int>gra[maxn],bcc[maxn];bool isb[maxn];void tarjan(int f,int u){ dfn[u]=low[u]=++cnt; int sz=gra[u].size(); for(int i=0;i<sz;i++){ int id=gra[u][i]; int v=edge[id].v; if(!dfn[v]){ tarjan(u,v); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]){ isb[id]=isb[id^1]=1; } }else if(dfn[v]<dfn[u]&&v!=f){ low[u]=min(low[u],dfn[v]); } }}void dfs(int u){ dfn[u]=1; bccno[u]=bcnt; int sz=gra[u].size(); for(int i=0;i<sz;i++){ int id=gra[u][i]; int v=edge[id].v; if(isb[id]){ continue; } if(!dfn[v]){ dfs(v); } }}int main(){ for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(-1,i); } } memset(dfn,0,sizeof(dfn)); for(int i=1;i<=n;i++){ if(!dfn[i]){ bcnt++; dfs(i); } }}
雙聯通的tarjan演算法