首先明白什么是强连通分量(SCC),然后考虑把有向图中的强连通分量缩成一个顶点,就得到了一个DAG(有向无环图),这就是强连通分量分解。
korasaju算法实现:通过两次DFS,第一次任取顶点作为起点,遍历所有未访问过的顶点,并在回溯前给顶点标号(后序遍历),对剩余未访问过的顶点,不断重复上述过程;
第二次DFS时,先将所有边反向,然后以标号最大的顶点为起点进行DFS,这样DFS所遍历的顶点集合就构成了一个强连通分量,对剩余未访问过的顶点,不断重复上述过程。
ps:反向后强连通的集合,还是强连通的。
时间复杂度:O(E+V)
其他分解算法:tarjan算法,Gabow算法
代码:
int V;//顶点数
vector<int> G[max_v];//图的邻接表表示
vector<int> rG[max_v];//图的逆邻接表表示
vector<int> vs;//后续遍历顺序的顶点列表
bool used[max_v);//访问标记
int cmp[max_v];//所属强连通分量的拓扑序
void add_edge(int from,int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int v)
{
used[v]=true;
for(int i=0;i<G[v].size();i++)
if(!used[G[v][i]])
dfs(G[v][i]);
vs.push_back(v);
}
void rdfs(int v,int k)
{
used[v]=true;
cmp[v]=k;
for(int i=0;i<rG[v].size();i++)
if(!used[rG[v][i]])
rdfs(rG[v][i],k);
}
int scc()//返回强连通分量个数
{
memset(used,0,sizeof(used));
vs.clear();
for(int v=0;v<V;v++)
if(!used[v[)
dfs(v);
memset(used,0,sizeof(used));
int k=0;
for(int i=vs.size()-1;i>=0;i--)
if(!used[vs[i]])
rdfs(vs[i],k++);
return k;
}