- 对于一个连通图G,如果任意两点间至少存在两条“点不重复”路径,则说这个图是点·双联通的。这个要求等价于图的内部无割顶。任意两边都在一个简单环中。
- 对于一张无向图,点·双联通图的极大子图(类似强连通分量)称为双联通分量(BCC)或块(block)。不同双联通分量至多有一个公共点,这个公共点是割顶。
- 注意,求出来的每一个双连通分量至少包含两个点。
- 计算双联通分量用Tarjan提出的如下算法,用一个栈来维护当前block中的边(其精髓与tarjan算法类似)。
int bccno[maxn],iscut[maxn],dfn[maxn],low[maxn],bccnt,stop,dindex;
vector<int> bcc[maxn];
edge sta[maxm];
void dfs(int u,int fa)
{
low[u]=dfn[u]=++dindex;
int child=0;
for(int i=last[u];i;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
child++;
sta[++stop]={u,v};
dfs(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
iscut[u]=1;
bccnt++;
bcc[bccnt].clear();
while(1)
{
edge x=sta[stop--];
if(bccno[x.u]!=bccnt)
{
bccno[x.u]=bccnt;
bcc[bccnt].pushback(x.u);
}
if(bccno[x.v]!=bccnt)
{
bccno[x.v]=bccnt;
bcc[bccnt].pushback(x.v);
}
if(x.u==u&&x.v==v) break;
}
}
}
else if(dfn[v]<dfn[u]&&v!=fa)
{
sta[++stop]={u,v};
low[u]=min(low[u],dfn[v]);
}
}
if(fa<0&&child==1) iscut[u]=0;
}
void findbcc()
{
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
}
- 通过简单的手动模拟得知,在dfs树中,简单环中只有一条反向边,较复杂的点·双连通分量反向边交错,如果原图是一条链,中间点都是割顶,则得到了一组只有两个点的“点·双连通分量”。