雲裡霧裡學Tarjan(強連通分量)
阿新 • • 發佈:2020-07-17
首先讓我先來說一說關於強連通分量的一些疑惑
1、當我已經知道了我要走的下一步節點在棧中,我能不能把比較中的DFN寫成LOW?
2、如果low[v]>=dfn[u],此時u就是割點,這個東西怎麼證明?
這裡連結兩篇Tarjan演算法寫的非常好的部落格:
↑洛谷有模板
下面是鄙人寫的裸的Tarjan求圖中強連通分量的程式碼!
//Tarjan基本的演算法實現 #include<bits/stdc++.h> using namespace std; struct sd{ int v,next; }edge[1001]; int DFN[1001],LOW[1001]; int stk[1001],head[1001],vis[1001],cnt,tot,index,n,m; void add(int x,int y) {//鏈式前向星 edge[++cnt].next=head[x]; edge[cnt].v=y; head[x]=cnt;return; } void tarjan(int x) { DFN[x]=LOW[x]=++tot; stk[++index]=x; vis[x]=1; for(int i=head[x];i;i=edge[i].next) { if(!DFN[edge[i].v]) tarjan(edge[i].v),LOW[x]=min(LOW[x],LOW[edge[i].v]); else if(vis[edge[i].v]) LOW[x]=min(LOW[x],DFN[edge[i].v]); } if(DFN[x]==LOW[x]) { while(stk[index]!=x) printf("%d ",stk[index]),vis[stk[index]]=0,index--; printf("%d\n",stk[index]),vis[stk[index]]=0,index--; } } int main() { scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;++i) { scanf("%d%d",&x,&y); add(x,y); } for(int i=1;i<=n;++i) { if(!DFN[i]) tarjan(i); } return 0; } /* 6 8 1 2 1 4 2 3 3 6 2 5 5 6 4 5 5 1 */
下面是我給出的求割點的tarjan演算法程式。我還是有一些東西沒有搞懂。(帶有註釋)
這裡給一張圖方便理解:(紅色的是DFN,藍色的是LOW)
//tarjan演算法求割點,我好像自己也不是很懂 #include<bits/stdc++.h> using namespace std; const int N=100010; struct sd{ int next,v; }edge[2*N]; int head[N],DFN[N],LOW[N],cnt=0,tot=0,n,m; bool judge[N]; void add(int x,int y) { edge[++cnt].next=head[x]; edge[cnt].v=y; head[x]=cnt; } void tarjan(int x,int fa) { int child=0; DFN[x]=LOW[x]=++tot; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].v;//v是要到達的點 if(!DFN[v]) { tarjan(v,fa); LOW[x]=min(LOW[x],LOW[v]); if(LOW[v]>=DFN[x]&&x!=fa)judge[x]=true;//就是說明下一個點的最早能追溯到的節點比當前點的dfs序大或等於 if(x==fa)child++;//找回來了,說明已經遍歷完了一顆子樹 } LOW[x]=min(LOW[x],DFN[v]);//?? 判斷回邊因為是無向圖!!!這裡不能改的過於大了不能改成LOW否則容易出問題! } if(child>=2&&x==fa)judge[x]=true; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } for(int i=1;i<=n;++i) if(!DFN[i])tarjan(i,i); int ans=0; for(int i=1;i<=n;++i) if(judge[i])ans++;printf("%d\n",ans); for(int i=1;i<=n;++i) if(judge[i])printf("%d ",i); return 0; }
By njc