有向图的强连通分量
- 什么是强连通?
强连通:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,即两点可以相互到达,则称两个顶点强连通。
- 什么是连通分量?
联通分量:有向图中任意两个不同顶点都可以相互到达(即任意两顶点都是强连通的)的子图称为一个连通分量。
- 什么是有向图的强连通分量?
有向图强连通分量:有向图的极大强连通分量,称为强连通分量。
- 强连通分量有什么用处?
可以通过将所有连通分量缩成一个点把任意一个有向图转化成一张有向无环图。
tarjan算法
Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度。
算法流程
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
算法模板
const int N = xxxx;
int n;
int h[N], e[M], ne[M], idx; //存图
int dfn[N], low[N], timeid; //时间戳
int stk[N], top; //模拟栈
int id[N], len[N], cnt; //每个节点所在连通分量标号, 每个连通分量内顶点数量, 连通分量数量
int dout[N], din[N]; //初度入度
bool st[N];
void tarjan(int u){
dfn[u] = low[u] = ++timeid;
stk[++top]=u;
st[u]=true;
for(int i=h[u]; i; i=ne[i]){
int j=e[i];
if(!dfn[j]){
tarjan(j);
low[u]=min(low[u], low[j]);
}
else if(st[j])
low[u]=min(low[u], dfn[j]);
}
if(dfn[u]==low[u]){
++cnt;
int y;
do{
y=stk[top--];
st[y]=false;
id[y]=cnt;
len[cnt]++;
}while(y!=u);
}
}