1. 程式人生 > >【圖論】tarjan

【圖論】tarjan

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;//表示在棧中。
 5
for(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