有向圖的強連通分量求法
阿新 • • 發佈:2020-08-17
https://byvoid.com/zhs/blog/scc-tarjan/,這裡講的tarjan已經很好了。
對於一個圖,說他是連通的當且僅當從該圖的任何一個頂點到該圖的另一個頂點都走得通,強連通的意思是,對於一個有向圖,任何一個頂點到另外一個頂點都能互通,強連通分量就是極大強連通子圖,可以這麼理解,對於該圖的某個頂點,當他加入一個點能構成連通圖時,就繼續加點,直到加不了為止,此時構成的原圖的一個子圖就叫極大強連通子圖,也叫強連通分量,一個圖可以有多個強連通分量。求強連通分量的基本思想就是dfs,解法包括但不限於Tarjan演算法、Kosaraju演算法,其中kosaraju演算法較為直觀,易於理解,我上面掛的連結就是講tarjan的。
下面給出一道例題以及AC程式碼:
http://poj.org/problem?id=1236
#pragma GCC optimize(2) #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <cmath> using namespace std; typedef long long ll; #define sc(z) scanf("%d", &(z)) #define _ff(i, a, b) for (int i = (a); i <= (b); ++i) #define _f(i, a, b) for (int i = (a); i < (b); ++i) #define _rr(i, a, b) for (int i = (a); i >= (b); --i) #define _r(i, a, b) for (int i = (a); i > (b); --i) #define pb push_back const int inf = 0x3f3f3f3f; const int maxn = 105; vector<int> G[maxn]; int dfn[maxn], low[maxn], dfncnt, s[maxn], instack[maxn], tp; int ssc[maxn], sc, n, in[maxn], out[maxn]; void tarjan(int u) { low[u] = dfn[u] = ++dfncnt, s[++tp] = u, instack[u] = 1; _f(i, 0, G[u].size()) { int v = G[u][i]; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v]){ low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { ++sc; while (s[tp] != u) { ssc[s[tp]] = sc; instack[s[tp]] = 0; --tp; } ssc[s[tp]] = sc; instack[s[tp]] = 0; --tp; } } void solve() { dfncnt = sc = tp = 0; _ff(i, 1, n) if (!dfn[i]) tarjan(i); } signed main() { int v; sc(n); _ff(i, 1, n) while(sc(v) && v) G[i].pb(v); solve(); _ff(i, 1, n) _f(j, 0, G[i].size()) { int k = G[i][j]; if (ssc[k] != ssc[i]) { in[ssc[k]]++; out[ssc[i]]++; } } if (sc == 1) printf("1\n0"); else { int x1 = 0, x2 = 0; _ff(i, 1, sc) { if (!in[i]) x1++; if (!out[i]) x2++; } printf("%d\n%d", x1, max(x1, x2)); } return 0; }