在Tarjan算法的過程當中維護一個棧,並按以下方法維護其中的元素
1:當一個節點第一次被訪問時,入棧。
2:當割點斷定法則中dfn[x]<=Low[y]成立時
不管X是否爲根,都要
1:從棧頂不斷頂出節點,直到節點Y被彈出
2:剛纔彈出的全部節點與節點X一塊兒構成一個V-DCC
注意節點X還在棧中ios
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N = 20010, M = 200010; int head[N], ver[M], Next[M]; int dfn[N], low[N], stack[N], new_id[N], c[N], belong[M]; int d[N], dist[N], f[N][16]; int n, m, t, tot, num, root, top, cnt, tc; bool cut[N]; vector<int> dcc[N]; int hc[N], vc[M], nc[M]; queue<int> q; void add(int x, int y) { ver[++tot] = y, Next[tot] = head[x], head[x] = tot; } void add_c(int x, int y) { vc[++tc] = y, nc[tc] = hc[x], hc[x] = tc; } void tarjan(int x) { dfn[x] = low[x] = ++num; stack[++top] = x; if (x == root && head[x] == 0) { dcc[++cnt].push_back(x); return; } int flag = 0; for (int i = head[x]; i; i = Next[i]) { int y = ver[i]; if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); if (low[y] >= dfn[x]) //x-->y,發現low[y]>=dfn[x],則X是一個割點 { flag++; if (x != root || flag > 1) //若是X不爲根,或者X爲根,但有兩個子樹時 cut[x] = true; cnt++; int z; do //將棧中的元素不斷彈出來,直到Y這個結點 { z = stack[top--]; dcc[cnt].push_back(z); } while (z != y); dcc[cnt].push_back(x);//將X這個點也加入點雙中,但X仍在棧中 } } else low[x] = min(low[x], dfn[y]); } } int main() { cin>>n>>m; memset(head, 0, sizeof(head)); memset(hc, 0, sizeof(hc)); memset(dfn, 0, sizeof(dfn)); memset(d, 0, sizeof(d)); memset(cut, 0, sizeof(cut)); memset(c, 0, sizeof(c)); for (int i = 1; i <= n; i++) dcc[i].clear(); tot = 1; num = cnt = top = 0; for (int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); add(x, y), add(y, x); } for (int i = 1; i <= n; i++) if (!dfn[i]) root = i, tarjan(i); for (int i=1;i<=cnt;i++) { cout<<"e-dcc "<<i<<endl; for (int j=0;j<dcc[i].size();j++) cout<<dcc[i][j]<<" "; cout<<endl; } } /* 4 4 1 2 2 4 2 3 3 4 */
運行結果算法
e-dcc 1
4 3 2
e-dcc 2
2 1spa