图算法(4)-强连通分量
一个图的连通分量即是这样的一个顶点集合,其中各个节点直接都可以相互到达连通。而强连通分量则是这样一个集合的极大值,即:添加任何另外节点,这个集合都不再是连通分量。
计算强连通分量,可以先对原图进行一次DFS遍历,计算得到每个节点的finish time。然后计算转置图,并对转置图进行DFS遍历(其中遍历的主循环,按照原图节点的finish time逆序),这样对转置图DFS遍历得到的每一棵深度遍历树的节点即为一个强连通分量。
算法如下:(用cout输出了强连通分量,每个强连通分量一行,DFS函数与前面相同,只是在最开始一行输出了当前节点)
1 void GraphTranspose(Graph& g, Graph& t) 2 { 3 t.nodemap = g.nodemap; 4 t.nodes.resize(g.nodes.size()); 5 for (size_t i = 0; i < g.nodes.size(); ++i) 6 { 7 t.nodes[i].value = g.nodes[i].value; 8 Edge e = { i }; 9 for (size_t j = 0; j < g.nodes[i].edges.size(); ++j) 10 { 11 t.nodes[g.nodes[i].edges[j].end].edges.push_back(e); 12 } 13 } 14 } 15 16 void GetOrder(Graph& g, vector<int>& order) 17 { 18 vector<Node*> s; 19 for (size_t i = 0; i < g.nodes.size(); ++i) 20 { 21 s.push_back(&g.nodes[i]); 22 } 23 sort(s.begin(), s.end(), cmp); 24 25 order.clear(); 26 for (size_t i = 0; i < s.size(); ++i) 27 { 28 order.push_back(g.nodemap[s[i]->value]); 29 } 30 } 31 32 void StronglyConnectedComponents(Graph& g) 33 { 34 DFS(g); 35 cout << endl; 36 vector<int> order; 37 GetOrder(g, order); 38 39 Graph t; 40 GraphTranspose(g, t); 41 42 for (size_t i = 0; i < t.nodes.size(); ++i) 43 { 44 t.nodes[i].p = -1; 45 t.nodes[i].color = WHITE; 46 } 47 48 time = 0; 49 for (size_t i = 0; i < order.size(); ++i) 50 { 51 int u = order[i]; 52 if (t.nodes[u].color == WHITE) 53 { 54 cout << "Comp : "; 55 DFS(t, u); 56 cout << endl; 57 } 58 } 59 }
最后运行可以看到结果。至于为什么不把强连通分量保存在数组里呢?因为太麻烦。。。。如果不用cout输出的话,需要DFS完后,根据p信息重建深度遍历树。
(终于明白为什么STL没有图算法了,因为图的各个问题形式不同,所需要添加的辅助信息也不一样,实在是很难用一个统一的结构表达出来。)