Tarjan-点双连通分量和边双连通分量
点双联通分量
若一个连通分量任意两点至少存在两条路径经过的点无重复(即除起终点外完全不同),则称为点双连通分量(DCC)(可理解为无重复点,两条路)。
定义无向图的割点为:如果去掉无向连通图 G \mathcal G G 中的一个点 u \mathcal u u 和所有和 u u u 相邻的边 ,剩下的子图 G ′ \mathcal G' G′ 不再是连通图,则称 w \mathcal w w 为一个割点。
因此,点双联通分量又可以简单地认为是:没有割点的连通分量
那么找点双连通分量,找割点就得了。
割点的判定法则
做 T a r j a n \tt Tarjan Tarjan,每次访问到一个节点就将其入栈。若有已入栈的点,重访问到了节点 t o to to,若 l o w [ t o ] > = d f n [ x ] low[to]>=dfn[x] low[to]>=dfn[x],则到 t o to to 的路径上全部出栈,将这批节点存入一个 D C C \mathcal DCC DCC。
感性地理解为:这个 x x x 点成为了一个断点,稍微推下就OK了。
Code:
缩点:
缩边:
void Tarjan(LL x,LL Pre)
{
Dfn[x] = Low[x] = ++ Cnt;
int l = G[x].size();
for (Int i = 0; i < l; ++ i)
{
LL to = G[x][i].v;
if (to == Pre)
continue;
if (! Dfn[to])
{
S.push( to ); S.push( x ); S.push( G[x][i].Index );
Tarjan(to, x);
Low[x] = Min(Low[x], Low[to]);
if (Low[to] >= Dfn[x]) // x 是割点
{
Col ++;
LL u, v;
do
{
Bian[Col].insert( S.top() ); S.pop();
u = S.top(); S.pop(); v = S.top(); S.pop();
Dian[Col].insert( u ); Dian[Col].insert( v );
} while (u != x || v != to);
}
}
else if (Dfn[to] < Dfn[x])
{
S.push( to ); S.push( x ); S.push( G[x][i].Index );
Low[x] = Min(Low[x], Dfn[to]);
}
}
}
边双连通分量
若一个连通分量任意两点至少存在两条路径经过的边无重复(即完全不同),则称为边双连通分量(可理解为无重复边,两条路)。
定义无向图的割边为:如果去掉无向连通图 G \mathcal G G 中的一条边 w \mathcal w w ,剩下的子图 G ′ \mathcal G' G′ 不再是连通图,则称 w \mathcal w w 为一条割边,又称为桥。
边双联通分量更简洁的表达方式为:内部无桥的连通分量。
那么对于判定边双连通分量,似乎只需要找桥就可以了。那么,如何进行桥的判定呢?
无向图的桥的判定法则
在无向图中,若边 e \mathcal e e (两端点为 u u u 和 v v v)为桥,只需要满足 d f n [ u ] < l o w [ v ] dfn[u]<low[v] dfn[u]<low[v]
我感性的理解是:若满足这个条件,在搜索树中, u u u 能走到 v v v,而 v v v 无法从下方搜索树到 u u u,那么形成了一个“断层”,即找到了这条边为桥。
那么如何进行边双连通分量的缩点呢?其实很简单,只需要将强连通分量的算法稍微改改——判一下不走返祖边就行了。
Code:
判定桥:(最好用前向星, v e c t o r \tt vector vector 不好存)
点双联通分量:
void Tarjan(LL x,LL Pre)
{
Dfn[x] = Low[x] = ++ Cnt;
S.push( x );
InStack[x] = 1;
int l = G[x].size();
for (Int i = 0; i < l; ++ i)
{
LL to = G[x][i];
if (to == Pre)
continue;
if (! Dfn[to])
{
Tarjan(to, x);
Low[x] = Min(Low[x], Low[to]);
}
else if ( InStack[to] )
Low[x] = Min(Low[x], Dfn[to]);
}
if (Dfn[x] == Low[x])
{
Col ++; LL u;
do
{
Size[Col] ++;
u = S.top();
S.pop();
InStack[u] = 0;
Bel[u] = Col;
} while(u != x);
}
}