有向图的强连通分量
两次dfs模板:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 #define M(a, b) memset(a, b, sizeof(a)) 5 const int N = 1000 + 5; 6 int vis[N], sccno[N], scc_cnt; 7 vector<int> G[N], G2[N]; 8 vector<int> S; 9 10 void dfs1(int u) { 11 if (vis[u]) return; 12 vis[u] = 1; 13 for (int i = 0; i < G[u].size(); ++i) dfs1(G[u][i]); 14 S.push_back(u); 15 } 16 17 void dfs2(int u) { 18 if (sccno[u]) return; 19 sccno[u] = scc_cnt; 20 for (int i = 0; i < G[u].size(); ++i) dfs2(G[u][i]); 21 } 22 23 void find_scc(int n) { 24 M(vis, 0); M(sccno, 0); 25 S.clear(); scc_cnt = 0; 26 for (int i = 0; i < n; ++i) dfs1(i); 27 for (int i = n-1; i >= 0; --i) 28 if (!sccno[i]) {++scc_cnt; dfs2(i);} 29 } 30 31 int main() { 32 int n, m; 33 while (cin >> n >> m) { 34 int u, v; 35 for (int i = 0; i < m; ++i) { 36 cin >> u >> v; 37 G[u].push_back(v); 38 G2[v].push_back(u); 39 } 40 find_scc(n); 41 } 42 43 return 0; 44 }
Tarjan算法模板:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define M(a, b) memset(a, b, sizeof(a)) 4 #define INF 0x3f3f3f3f 5 const int N = 1000 + 5; 6 int pre[N], sccno[N], dfs_clock, scc_cnt; 7 vector<int> G[N]; 8 stack<int> S; 9 10 int dfs(int u) { 11 int lowu = pre[u] = ++dfs_clock; 12 S.push(u); 13 for (int i = 0; i < G[u].size(); ++i) { 14 int v = G[u][i]; 15 if (!pre[v]) { 16 int lowv = dfs(v); 17 lowu = min(lowu, lowv); 18 } 19 else if (!sccno[v]) { //加这个判定条件去掉已经包含在其他强连通分量中的反向边 20 lowu = min(lowu, pre[v]); 21 } 22 } 23 if (lowu == pre[u]) { 24 ++scc_cnt; 25 while (true) { 26 int x = S.top(); S.pop(); 27 sccno[x] = scc_cnt; 28 if (x == u) break; 29 } 30 } 31 return lowu; 32 } 33 34 void find_scc(int n) { 35 M(pre, 0); M(sccno, 0); 36 dfs_clock = scc_cnt = 0; 37 for (int i = 0; i < n; ++i) 38 if (!pre[i]) dfs(i); 39 } 40 41 int main() { 42 int n, m; 43 while (cin >> n >> m) { 44 int u, v; 45 for (int i = 0; i < m; ++i) { 46 cin >> u >> v; 47 G[u].push_back(v); 48 } 49 find_scc(n); 50 } 51 52 return 0; 53 }