【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;}