给定一个有向图,要求寻找全部强联通分量。
首先要先明确几点:
1.点a和点b连通 当且仅当 存在边(a,b)和(b,a)
2.将一个有向图的所有强连通分量看成顶点,则该图是有向无环图(dag)。
如下图:
还有明确几点性质:
1.对一个"聚点"(强连通分量)的点进行DFS,则不会跑出这个连通分量。因为没有边可以出去。(如上图的h连通分量)
2.DFS后,post值最高的为源点
所以我们的思路可以是这样,找到聚点(某个点),DFS它,由性质1可知,能被访问的点组成的就是一个强连通分量。删除它(因为是dag,所以必定会有新的聚点),再找聚点……
如何找到聚点呢?我们可以先把图G的边取反,记为GT,找到GT的源点,则为G的聚点,源点的寻找方法由性质2得到。
所以算法如下:
1.对G进行DFS,更新post数组。
2.计算GT。
3.对GT进行DFS,不过要按照post值递减的顺序进行explore。
代码贴上
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <vector> #include <algorithm> using namespace std; #define Max 100 int n, m; //n为点数,m为边数 int clk; //用于更新pre post int pre[Max], post[Max]; bool vis[Max]; vector<int> v[Max]; //邻接表 vector<int> v2[Max]; int post2[Max]; pair<int, int> p[Max];//用于得到post2 bool cmp(pair<int, int> a, pair<int, int> b) { return a.second >= b.second; } //更新post2,按post递减的顺序存post的下标 void sortPost() { for (int i = 1; i <= n; ++i) { p[i].first = i; p[i].second = post[i]; } sort(p+1, p+n+1, cmp); for (int i = 1; i <= n; ++i) post2[i] = p[i].first; } //对G中的边取反 void G_T() { for (int i = 1; i <= n; ++i) { for (int j = 0; j < v[i].size(); ++j) { v2[v[i][j]].push_back(i); } } } void post_vis(int x) { post[x] = clk; clk++; } void explore(int x) { vis[x] = true; for (int i = 0; i < v[x].size(); ++i) { if (!vis[v[x][i]]) { explore(v[x][i]); } } post_vis(x); } void dfs() { //init clk = 1; for (int i = 1; i <= n; ++i) vis[i] = false; //explore for (int i = 1; i <= n; ++i) if (!vis[i]) explore(i); //explore次数为连通分量次数 } void output() { cout << endl; } void explore2(int x) { vis[x] = true; for (int i = 0; i < v2[x].size(); ++i) if (!vis[v2[x][i]]) explore2(v2[x][i]); cout << x << ' '; } void dfs2() { //init for (int i = 1; i <= n; ++i) vis[i] = false; sortPost(); //explore 按post递减顺序 for (int i = 1; i <= n; ++i) { if (!vis[post2[i]]) { explore2(post2[i]); output();//到这里得到一个强连通分量 } } } int main() { cin >> n >> m; int a,b; for (int i = 0; i < m; ++i) { cin >> a >> b; v[a].push_back(b); } dfs(); G_T(); dfs2(); system("pause"); }
测试数据
8 14
1 2 2 3 3 4 4 3
5 1 2 5 2 6 3 7 4 8
5 6 6 7 7 6 7 8 8 8