hdu 3352 求边双联通分量模板题(容器)

/*这道题是没有重边的,求加几条边构成双联通,求边联通分量,先求出桥然后缩点,成一个棵树
找叶子节点的个数*/
#include<stdio.h>
#include<string.h>
#define N  1100
int top[N],ma[N][N],dfn[N],low[N],index,f[N][N],n;
int Min(int a,int b) {
return a>b?b:a;
}
void tarjan(int u,int pre) {//
 dfn[u]=low[u]=++index;
 int i;
 for(i=0;i<top[u];i++) {
    int v=ma[u][i];
    if(v==pre)continue;
    if(!dfn[v]) {
        tarjan(v,u);
        low[u]=Min(low[u],low[v]);//
        if(low[v]>dfn[u])//标记桥
            f[u][v]=f[v][u]=1;
    }
    else
        low[u]=Min(low[u],dfn[v]);
 }
}
int cnt,c[N];
void dfs(int u,int fa) {//缩点
int i;
 c[u]=cnt;//不能放到循环里面,
for(i=0;i<top[u];i++) {
        int v=ma[u][i];
    if(!f[u][v]&&!c[v]&&v!=fa)//桥不能走,不能回头路,没有被缩过
        dfs(v,u);
}
return ;
}
int degree[N];
int slove() {
    int i,j,b;
    cnt=1;
    memset(c,0,sizeof(c));
    for(i=1;i<=n;i++)//缩点
            if(!c[i]) {
        dfs(i,-1);
        cnt++;
            }
    memset(degree,0,sizeof(degree));
    for(i=1;i<=n;i++)
        for(j=0;j<top[i];j++){
                b=ma[i][j];
            if(c[i]!=c[b]) {//所有边中
                degree[c[i]]++;
                degree[c[b]]++;//记录度数
            }
    }
    int leave=0;
    for(i=1;i<cnt;i++) {//度数为一的叶子节点,因为为双向边
        if(degree[i]==2)
            leave++;
    }
    return  (leave+1)/2;
}
int main() {
   int m,i,a,b,ans;
   while(scanf("%d%d",&n,&m)!=EOF) {
    memset(top,0,sizeof(top));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(f,0,sizeof(f));
    index=0;
    while(m--){
        scanf("%d%d",&a,&b);
        ma[a][top[a]++]=b;//容器
        ma[b][top[b]++]=a;
    }
    for(i=1;i<=n;i++)
        if(!dfn[i])
        tarjan(i,-1);
        ans=slove();
        printf("%d
",ans);
   }
return 0;
}

原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410694.html