图论$\cdot$强连通分量

和无向图的连通分量类似,有向图有“强连通分量”的说法。“相互可达”的关系在有向图中也是等价关系。每一个集合称为有向图的一个强连通分量(scc)。如果把一个集合看成一个点,那么所有的scc构成了一个scc图。这个scc图不会存在任何有向环,因此是一个DAG。求解有向图强连通分量的算法一般都是基于dfs的,常用的算法有Kosaraju算法和Tarjan算法,下面给出Tarjan算法的代码:

 1 vector<int> G[maxn];
 2 int pre[maxn], low_link[maxn], scc_no[maxn], dfs_clk, scc_cnt;
 3 stack<int> S;
 4 void dfs(int u){
 5     pre[u] = low_link[u] = ++dfs_clk;
 6     S.push(u);
 7     FOR(i, 0, G[u].size() - 1){
 8         int v = G[u][i];
 9         if(!pre[v]){
10             dfs(v);
11             minimize(low_link[u], low_link[v]);
12         }else if(!scc_no[v]) minimize(low_link[u], pre[v]);
13     }
14     if(low_link[u] == pre[u]){
15         scc_cnt++;
16         while(true){
17             int x = S.top(); S.pop();
18             scc_no[x] = scc_cnt;
19             if(x == u) break;
20         }
21     }
22 }
23 void find_scc(int n){
24     dfs_clk = scc_cnt = 0;
25     clr(scc_no, 0), clr(pre, 0);
26     FOR(i, 0, n - 1) if(!pre[i]) dfs(i);
27 }

 由于每个点恰属于一个scc,因此我们希望在第一次访问某scc的结点并完成时就将该scc输出。所有需要判断某个点是否是其所在scc中最先被发现的点。与计算无向图bcc方法类似,对于每个结点$u$用$lowlink(u)$表示$u$及其后代能够追溯到最早的祖先点$v$的$pre(v)$的值。因此$u$是第一个被发现的点当且仅当$lowlink(u) =pre(u)$。

posted @ 2016-08-11 23:29  astoninfer  阅读(357)  评论(0编辑  收藏  举报