【圖論】tarjan
阿新 • • 發佈:2018-05-20
AS code 更新 out 聯通 ace 起點 是什麽 環路
剛接觸tarjan,tarjan其實更多是用來找強聯通分量。我這裏呢,是看qsc的視頻學的。卿學姐講的其實很清楚啦。
我這裏只是做個整理。
low[]:表示能到達這個點的最小編號。[樹枝邊]。啊,其實我覺得就是保存環路的起點。QWQ。因為只要記錄了這個點,棧中經歷的點都能到達嘛都是強聯通啊。
dfn[]:搜索到這個點的時間是多少。[後叉邊]。時間戳。
vis[]:該點是否進棧。
偽代碼如下:
1 tarjan(x) 2 low[x] = dfn[x] = ++index; 3 stack.push(x); 4 vis[x] = 1;//表示在棧中。 5for(v屬於E){ 6 if(vis[v] == 0) 7 tarjan(v),low[x] = min(low[x],low[v]); 8 if(vis[v]){ 9 low[x] = min(low[x],dfn[v]); 10 } 11 } 12 13 if(low[x] == dfn[x]){ //這裏其實就是表示點已經通過某一種方式到達了自己 14 做出棧操作 15 }
這裏主要就是在兩個if中要理解。
如果該點沒有進棧,當前存的當然要是最短的。
如果該點進棧了,就去看他的dfn[]存的是什麽,就更新。
具體的舉例請看卿學姐的視頻啊。QWQ。。有時間我補圖上來。。
例題題目鏈接:NOIP2015信息傳遞
代碼:
#include<iostream> #include<algorithm> #include<vector> #include<queue> #include<stack> using namespace std; const int maxn = 2e5+7; vector<int> E[maxn]; int dfn[maxn],low[maxn],tot = 0,n,ans = maxn; stack<int> S; int vis[maxn]; void tarjan(int x){ low[x] = dfn[x] = tot++; S.push(x); vis[x] = 1; for(int i = 0 ; i < E[x].size() ;i++){ int v = E[x][i]; if(!dfn[v]){ tarjan(v); low[x] = min(low[x],low[v]); } else if(vis[v]){ low[x] = min(low[x],dfn[v]); } } if(low[x] == dfn[x]){ int cnt = 0; while(1){ int now = S.top(); S.pop(); vis[x] = 0; cnt++; if(now == x){ break; } } if(cnt > 1 ) ans = min(ans,cnt); } } int main(){ cin>>n; for(int i = 1; i <= n ;i++){ int x; cin>>x; E[i].push_back(x); } for(int i = 1; i <= n ;i++){ if(!dfn[i]){ tarjan(i); } } cout<<ans<<endl; return 0; }
【圖論】tarjan