tarjan演算法與拓撲排序
阿新 • • 發佈:2020-07-11
演算法介紹
tarjan
tarjan演算法要求使有向圖。
Tarjan就是一個輔助作用,把有環圖縮為無環圖,也就是將強聯通分量縮成一個點。
幾個陣列 dfn時間戳,low仍在棧中的最小時間戳,dag縮點後的陣列,ins是否在棧中。
void tarjan(int x) { dfn[x]=low[x]=++cnt; ins[x]=1; st.push(x); for(int i=0;i<g[x].size();i++) { int q=g[x][i]; if(dfn[q]==0) { tarjan(q); low[x]=min(low[x],low[q]); } else if(ins[q]==1) { low[x]=min(low[x],dfn[q]); } } if(dfn[x]==low[x]) { numb++; int q; do { q=st.top(); st.pop(); ins[q]=0; dag[q]=numb; num[numb]++; p[numb]+=a[q]; } while(q!=x); } }
拓撲排序
對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊<u,v>∈E(G),則u線上性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序。
拓撲排序步驟
統計入度,入度為0入棧,遞推並更新入度,入度為0入棧,棧空結束
queue<int>q; int tot=0; for(int i=1;i<=numb;i++) { if(!ind[i]) { q.push(i); dist[i]=p[i]; } } while(!q.empty()) { int k=q.front();q.pop(); for(int i=0;i<g1[k].size();i++) { int v=g1[k][i]; dist[v]=max(dist[v],dist[k]+p[v]); ind[v]--; if(ind[v]==0)q.push(v); } }
例題
程式碼
const int maxn=100015; int numb,cnt; int dist[maxn]; int dag[maxn],num[maxn]; int a[maxn]; int ind[maxn]; stack<int>st; int p[maxn],dfn[maxn],ins[100015],low[100015]; vector<int>g[maxn],g1[maxn]; void tarjan(int x) { dfn[x]=low[x]=++cnt; ins[x]=1; st.push(x); for(int i=0;i<g[x].size();i++) { int q=g[x][i]; if(dfn[q]==0) { tarjan(q); low[x]=min(low[x],low[q]); } else if(ins[q]==1) { low[x]=min(low[x],dfn[q]); } } if(dfn[x]==low[x]) { numb++; int q; do { q=st.top(); st.pop(); ins[q]=0; dag[q]=numb; num[numb]++; p[numb]+=a[q]; } while(q!=x); } } main(void) { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } for(int i=1;i<=m;i++) { int u,v; cin>>u>>v; g[u].push_back(v); } for(int i=1;i<=n;i++) { if(!dag[i]) tarjan(i); } for(int i=1;i<=n;i++) for(int j=0;j<g[i].size();j++) { int u=dag[i],v=dag[g[i][j]]; if(u!=v) { g1[u].push_back(v); ind[v]++; } } queue<int>q; int tot=0; for(int i=1;i<=numb;i++) { if(!ind[i]) { q.push(i); dist[i]=p[i]; } } while(!q.empty()) { int k=q.front();q.pop(); for(int i=0;i<g1[k].size();i++) { int v=g1[k][i]; dist[v]=max(dist[v],dist[k]+p[v]); ind[v]--; if(ind[v]==0)q.push(v); } } int ans=0; for(int i=1;i<=numb;i++) ans=max(ans,dist[i]); cout<<ans; }