无向图点双+缩点

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct my{
    int next;
    int v;
};

const int maxn=10000;
int low[maxn],dfsn[maxn],adj[maxn],fa,sfa,dfn;
int bs[maxn],cnt;
bool bridge[maxn*2];
int sadj[maxn];
my sbian[maxn*2];
my bian[maxn*2];

void myinsert(int u,int v){
     bian[++fa].v=v;
     bian[fa].next=adj[u];
     adj[u]=fa;
}

void smyinsert(int u,int v){
     sbian[++sfa].v=v;
     sbian[sfa].next=sadj[u];
     sadj[u]=sfa;
}

void tarjan(int x,int dage){
     dfsn[x]=low[x]=++dfn;
     for (int i=adj[x];i;i=bian[i].next){
        int v=bian[i].v;
        if(!dfsn[v]){
            tarjan(v,i);
            low[x]=min(low[x],low[v]);
            if(dfsn[x]<low[v]){
                bridge[i]=bridge[i^1]=1;
            }
        }
        else if(i!=(dage^1)){
            low[x]=min(low[x],dfsn[v]);
        }
     }
}

void dfs(int x){
     bs[x]=cnt;
     for (int i=adj[x];i;i=bian[i].next){
        int v=bian[i].v;
        if(bs[v]||bridge[i]) continue;
        dfs(v);
     }
}

int main(){
    int n,m;
    int u,v;
    fa=1;
    sfa=1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        myinsert(u,v);
        myinsert(v,u);
    }
    for (int i=1;i<=n;i++) if(!dfsn[i]) tarjan(i,0);
    for (int i=1;i<=n;i++){
        if(!bs[i]){
            cnt++;
            dfs(i);
        }
    }
    //for (int i=2;i<fa;i+=2) if(bridge[i]) printf("%d %d
",bian[i].v,bian[i^1].v);
    for (int i=2;i<=fa;i++){
            int x=bian[i].v,y=bian[i^1].v;
        if(bs[x]==bs[y]) continue;
                smyinsert(bs[x],bs[y]);//不需连两条边,算法自己会连成双向边
    }
    for (int i=1;i<=cnt;i++){
            printf("%d ",i);
        for (int j=sadj[i];j;j=sbian[j].next){
             printf("%d ",sbian[j].v);
        }
        printf("
");
    }

return 0;
}
原文地址:https://www.cnblogs.com/lmjer/p/8687817.html