图的连通性【模板】

时间:2021-06-21 12:41:03

图的连通性【模板】

强连通分量【有向图】

强连通图:图G中任意两点之间都有可以到达的路径

强连通分量:有向图G的最大连通子图

最大连通子图:该子图是G的强连通子图,且将G中的任意一个不在该图中的点加入该子图中该子图将不再连通。

stack<int>s;
void Tarjan(int u){
    Time++;
    Dfn[u]=Time,Low[u]=Time;
    s.push(u),Instack[u]=true;//标记点是否在栈中 
    for(int i=Last[u];i;i=Next[i]){
        int v=End[i];
        if(!Dfn[v]){
            Tarjan(v);
            Low[u]=min(Low[u],Low[v]);
        }else if(Instack[v])//<u,v>是返祖边 
            Low[u]=min(Low[u],Dfn[v]);
        if(Dfn[u]==Low[u]){//退栈 ,弹出整个强连通分量 
            int v;scc++;
            do{
                v=s.top(),s.pop();
                Belong[v]=scc;//v属于scc号强连通分量 
                Instack[v]=false;
            }while(u!=v);
        }
    }
}

割点【无向图】

无向连通图中的一个顶点u,若删去它以及其关联边,得到的新图至少包含两个连通分量。

条件:

①u是树根(搜索树),且至少有两棵子树

②u不是树根,且存在(u,v)使得Dfn[u]<=Low[v]

void Tarjan(int u,int fa){//fa是u的父亲 
    Time++;
    Dfn[u]=Time,Low[u]=Time;
    for(int i=Last[u];i;i=Next[i]){
        int v=End[i];
        if(!Dfn[v]){
            Son[u]++;
            Tarjan(v,u);
            Son[u]+=Son[v];
            //要排除u是根节点的情况,最后特判 
            if(Dfn[u]<=Low[v] && fa)cutP[u]=true;
        }else if(v!=fa)//返祖边 
            Low[u]=min(Low[u],Dfn[v]);
    }
    if(!fa && Son[u]>1)cutP[u]=true;//u是树根,且至少有两个儿子 
}

割边【无向图】

无向图中的一条边,删除它之后的新图将至少包含两个连通分量。

条件:

对于(u,v),有Dfn[u]

void Tarjan(int u,int fa){
    Time++;
    Low[u]=Time,Dfn[u]=Time;
    for(int i=Last[u];i;i=Next[i]){
        int v=End[i];
        if(!Dfn[u]){
            Tarjan(v,u);
            Low[u]=min(Low[u],Low[v]);
            if(Dfn[u]<Low[v])
                Bridge[++cnt].x=u,Bridge[++cnt].y=v;
        }else if(v!=fa)
            Low[u]=min(Low[u],Dfn[v]);
    }
}