一、强连通分量
Gt.
1.1 有向图的一些定理
-
有向无环图中唯一出度为0的点,一定可以由任何点出发到达
图中节点的数目为有限多个,而且无环,因此从任何点出发往前走,一定终止于出度为0的点,否则走N+1步(N为图中节点的数目),则必然有一个点被走了两次,形成了环,与无环矛盾! -
有向无环图中所有入度不为0的点,一定可以由某个入度为0的点出发可达
由于无环,所以从任何入度不为0的点往回走,必然终止于一个入度为0的点。
1.2 强连通分量的求解
一个有向图G可以存在多个极大连通子图,即多个强连通分支。求一个有向图的强连通分支的方法主要有:Korasaju算法和Tarjan算法。
3. 第2步中产生的标记值相同的节点构成深度优先森林中的一棵树,也即一个强连通分量
(2)如果一个节点u,从其出发进行的DFS已经全部完成并回到u,而且此时 low[u] == dfn[u],说明u可达的所有节点,都不能到达任何比u早的节点——那么,该节点u就是一个强连通分量在DFS搜索树中的根。此时,显然栈中u上方的节点,都是不能到达比u早的节点的。将栈中节点弹出,一直弹到u(包括u),弹出的节点就构成了一个强连通分量。
void Tarjan(int u){
dfn[u] = low[u] = ++index;
stack.push(u);
for each(u,v) in E{
if (v is not visited){
Tarjan(v);
low[u] = min(low[u], low[v]);
}else if (v in stack){
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]){ //u是一个强连通分量的根
repeat
v = stack.pop
print v
until (u == v)
}//退栈,把整个强连通分量都弹出来
}
二、割点和桥
无向连通图中,如果删除某边后,图变成不连通,则称该边为桥
求割点和桥的Tarjan算法
(2)u不为树根,且存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得 dfn(u) <= low(v)
(u,v)为树枝边,且满足dfn(u) < low(v)。注意,(u,v)不能有重边。
Tarjan算法在DFS过程中判断割点或桥
void Tarjan(u){
dfn[u] = low[u] = ++index;
for each(u,v) in E{
if (v is not visited){
Tarjan(v)
low[u] = min(low[u], low[v])
if(d[u] < low[v])
(u,v)为桥
}else if (v 不是 u的父节点){
low[u] = min(low[u], dfn[v]);
}
}
if (u 为根)
u是割点 <=> u 有至少两个子节点
else
u是割点 <=> u 有一个子节点v,满足 dfn[u] <= low[v]
}
找桥的时候,需要注意有无重边,若有重边,则不是桥。
三、无向连通图点双连通分支
3. 割点可以属于多个点双连通分支,其余点和每条边只能属于一个点双连通分支
四、无向连通图边连通分支
桥不属于任何一个边连通分支,其余的边和每个顶点都属于且只属于一个边连通分支。