【tarjan双连通求割点&连通分量】POJ 1523

来源:互联网 发布:能下载ed2k的软件 编辑:程序博客网 时间:2024/05/17 03:28
/*构建一棵dfs树,序列dfn[i]为深度优先数,表示dfs时访问i节点的序号,low[i]表示从i节点出发能访问到的最小的深度优先数。当且仅当节点u满足如下两个条件之一时,u为割点:1.u为dfs树的根,且u至少有两个子节点。2.u不是dfs树的根,至少存在一个节点v是u的子节点,且low[v]>=dfn[u]。若u为割点,记subnets[u]为u的子节点数,则去掉u后,图被分成subnets[u]+1个部分(每个子节点的部分和u的祖先的部分),若u为dfs树的根,则分成subnets[u]个部分(根节点没有祖先)。以上全部算法均在dfs过程中完成。*/#define N 1010struct edge{    int v;    int next;}e[N*5];int ecnt;int head[N];void init(){    ecnt = 0;    memset(head,-1,sizeof(head));}void add(int u,int v){    e[ecnt].v = v;    e[ecnt].next = head[u];    head[u] = ecnt++;    e[ecnt].v = u;    e[ecnt].next = head[v];    head[v] = ecnt++;}int low[N],dfn[N];int cut[N];int n,m;int t;int ans;int sub[N];//tarjan求无向图双连通图void tarjan(int u,int fa){    low[u] = dfn[u] = ++t;    int i;    for(i=head[u];i!=-1;i=e[i].next){        int v = e[i].v;        if(v == fa)continue;        if(!dfn[v]){            tarjan(v,u);            low[u] = min(low[u],low[v]);            if(dfn[u]<=low[v]){//u是割点                if(u!=1)sub[u]++;//假定1为根结点                else ans++;            }        } else low[u] = min(low[u],dfn[v]);//返祖边    }}int main(){    int a,b;    int ca=1;    while(1){        scanf("%d",&a);        if(!a)break;        init();        memset(dfn,0,sizeof(dfn));        scanf("%d",&b);        add(a,b);        int node = 0;        node = max(a,b);        while(scanf("%d",&a) && a){            scanf("%d",&b);            add(a,b);            node = max(node,max(a,b));        }        int i,j;        ans=t=0;        memset(sub,0,sizeof(sub));        tarjan(1,1);//假定1为根结点        if(ca>1)puts("");        printf("Network #%d\n",ca++);cout<<ans<<endl;        if(ans>1)sub[1] = ans-1;//根至少有两个儿子才算是割点        bool ok=0;        for(i=1;i<=node;i++){            if(sub[i]){                ok  = 1;                printf("  SPF node %d leaves %d subnets\n",i,sub[i]+1);            }        }        if(!ok)puts("  No SPF nodes");    }    return 0;}



















原创粉丝点击