您的位置:首页 > 其它

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

2012-02-10 01:36 363 查看
/*
构建一棵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 1010
struct edge{
int v;
int next;
}e[N*5];
int ecnt;
int head
;
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
,dfn
;
int cut
;
int n,m;
int t;
int ans;
int sub
;
//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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: