poj 2117 去掉割点可以分得的联通图的个数模板

#include<stdio.h>
#include<string.h>
#define N  11000
/*
去掉一个割点后,询问可以分得的联通图的个数
*/
struct node {
int u,v,next;
}bian[N*100];
/*cut数组记录去掉某个节点后可以增加的联通分支的个数,num数组记录以i为根节点的联通图的元素的个数*/
int head[N],n,yong,cou,index,dfn[N],low[N],cut[N],num[N];
void init() {
yong=0;index=0;cou=0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(num,0,sizeof(num));
memset(cut,0,sizeof(cut));
}
int Min(int a,int b) {
return a>b?b:a;
}
void addedge(int u,int v) {
bian[yong].u=u;
bian[yong].v=v;
bian[yong].next=head[u];
head[u]=yong++;
}
void tarjan(int u,int pre) {
int i;
dfn[u]=low[u]=++index;
cou++;
if(pre<0)//根节点去掉后无影响,或则单个孤立节点的计算标记
    cut[u]--;
for(i=head[u];i!=-1;i=bian[i].next) {
    int v=bian[i].v;
    if(!dfn[v]) {
        tarjan(v,u);
        low[u]=Min(low[u],low[v]);
        if(low[v]>=dfn[u])//割点去掉后可增加联通分量
            cut[u]++;
    }
    else
        low[u]=Min(low[u],dfn[v]);
}
}
int main(){
   int m,a,b,i,flag,ans,sum;
   while(scanf("%d%d",&n,&m),n||m) {
        init();
    while(m--) {
        scanf("%d%d",&a,&b);
        a++;b++;
        addedge(a,b);
        addedge(b,a);
    }
    sum=0;
    for(i=1;i<=n;i++)
    if(!dfn[i]) {
        cou=0;
        sum++;//记录有多少个联通块
        tarjan(i,-1);
        num[i]=cou;//记录以i为根节点的联通分量的元素的个数
    }
    int flag=-1;
   ans=0;
   for(i=1;i<=n;i++)
    if(cut[i]) {//只判断有影响的点包括割点,单独孤立的点等
        if(ans<cut[i]+1) {//计算可以增加的联通分量
            flag=i;
            ans=cut[i]+1;
        }
    }
    if(flag==-1) {//如果不能增加,如全部是孤立的节点,或者双联通这样的特殊情况
        flag=0;
        for(i=1;i<=n;i++)
            if(num[i]>1)//是否双联通这种情况,去掉任意一个不影响结果
            flag++;
            if(flag)
                printf("%d\n",sum);
            else
                printf("%d\n",sum-1);//说明全部都是孤立的点
    }
    else
        printf("%d\n",ans+sum-1);
   }
return 0;
}

posted @ 2014-07-20 14:43  HYDhyd  阅读(133)  评论(0编辑  收藏  举报