首页 > 代码库 > 无向图双连通分量 模板

无向图双连通分量 模板

//点-双连通分量模板。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
struct Edge
{
    int u,v;
};//u,v是边的两个端点
const int maxn=100005;
int n,m;
int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
//pre[i]记录i点的编号,iscut[i]标记i点是不是割点,bccno[i]记录i点所属的双连通分量
//bcc_cnt,双联通分量计数器
vector<int>G[maxn],bcc[maxn];//G存原图,bcc[i]存第i个连通分量中的点
stack<Edge>s;
int dfs(int u,int fa)//u和u的父亲
{
    int lowu=pre[u]=++dfs_clock;
    int child=0;
    for(int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        Edge e=(Edge){u,v};
        if(!pre[v]){//没有访问过v
            s.push(e);
            child++;
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);//用后代的low函数更新自己
            if(lowv>=pre[u]){
                iscut[u]=true;
                bcc_cnt++;  //bcc从1开始编号
                bcc[bcc_cnt].clear();
                for(;;){
                    Edge x=s.top();
                    s.pop();
                    if(bccno[x.u]!=bcc_cnt) {bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
                    if(bccno[x.v]!=bcc_cnt) {bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
                    if(x.u==u&&x.v==v) break;
                }
            }
        }
        else if(pre[v]<pre[u]&&v!=fa){
            s.push(e);
            lowu=min(lowu,pre[v]);//用反向边更新自己
        }
    }
    if(fa<0&&child==1) iscut[u]=0;
    return lowu;
}
void find_bcc()
{
    //调用结束后s保证为空,所以不用清空
    memset(pre,0,sizeof(pre));
    memset(iscut,0,sizeof(iscut));
    memset(bccno,0,sizeof(bccno));
    dfs_clock=bcc_cnt=0;
    for(int i=0;i<n;i++)
        if(!pre[i]) dfs(i,-1);
}
int main()
{
    /*
    int a,b;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    find_bcc();
    for(int i=0;i<n;i++){
        cout<<bccno[i]<<endl;
    }
    for(int i=1;i<=bcc_cnt;i++){
        for(int j=0;j<(int)bcc[i].size();j++){
            cout<<bcc[i][j]<<" ";
        }
        cout<<endl;
    }
    for(int i=0;i<n;i++) cout<<iscut[i]<<endl;
    */
    return 0;
}

 

无向图双连通分量 模板