pku 3352 Road Construction(构造边双连通分量)

给定无图,构造边双连通分量。

此题不像3177,没有重边,不用判重

思路:去掉桥,则得到一个个边双连通分量,将它们缩成一个点,此时再加上原来的桥,则构成一棵树,记树中的叶子数为leaf,则最少要加上(leaf+1)/2条边才能构造出边双连通分量。

#include <stdio.h>
#include <string.h>

 

#define MAXN 1001
#define MAXM 1001*2

 

//并查集
int father[MAXN];
int find_mfs(int x)
{
    int i;
    for(i=x; father[i]>0; i=father[i]) ;
    //路径压缩
    while(x!=i)
    {
        int t=father[x];
        father[x]=i;
        x=t;
    }
    return i;
}
void merge_mfs(int x,int y)
{
    int fx,fy;
    fx=find_mfs(x);
    fy=find_mfs(y);
    if(fx==fy) return;
    if(father[fx]>father[fy])//例如-3>-4,但绝对值3<4
    {
        father[fy]+=father[fx];
        father[fx]=fy;
    }
    else
    {
        father[fx]+=father[fy];
        father[fy]=fx;
    }
}

struct edge
{
    int adv,next;
};
edge p[MAXM];
int index;

int adjlist[MAXN];
int N,M,times,dfn[MAXN],low[MAXN],degree[MAXN];

inline void insert(int i,int j)
{
    p[index].adv=j;
    p[index].next=adjlist[i];
    adjlist[i]=index++;
}

void print()
{
    int i,j;
    for(i=1; i<=N; i++)
    {
        printf("%d : ",i);
        for(j=adjlist[i]; j != -1; j=p[j].next)
        {
            printf("%d ",p[j].adv);
        }
        printf("\n");
    }
}

inline int Min(int a,int b)
{
    return a<b?a:b;
}

void dfs(int u,int ufa)
{
    dfn[u]=low[u]=++times;
    for(int j=adjlist[u]; j != -1; j=p[j].next)
    {
        int v=p[j].adv;
        if( !dfn[v] )
        {
            dfs(v,u);
            low[u]=Min(low[u],low[v]);
            if( ! (dfn[u] < low[v]) )//(u,v)不是桥
            {
                //则u、v属于同一个边双连通分量(此题不需要判重边)
                merge_mfs(u,v);
            }
        }
        else if(v!=ufa)
        {
            low[u]=Min(low[u],dfn[v]);
        }
    }
}

void shrink(int &bcn)
{
    int i,j,ifather,jfather;
    for(i=1; i<=N; i++)
    {
        ifather=find_mfs(i);
        for(j=adjlist[i]; j != -1; j=p[j].next)
        {
            jfather=find_mfs(p[j].adv);
            if(ifather != jfather)
            {
                degree[jfather]++;
                if(jfather>bcn) bcn=jfather;
            }
        }
    }
}

int main()
{
    int i,j;
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        index=0;
        memset(adjlist,-1,sizeof(adjlist));
        while(M--)
        {
            scanf("%d %d",&i,&j);
            insert(i,j);
            insert(j,i);
        }
        //  print();
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        times=0;
        memset(father,-1,sizeof(father));
        dfs(1,-1);
        memset(degree,0,sizeof(degree));
        int bcnt=-1;
        shrink(bcnt);
        for(i=1,j=0; i<=bcnt; i++)
        {
            if(degree[ i ] == 1) j++;
        }
        printf("%d\n",(j+1)/2);
    }
    return 0;
}

 

posted @ 2010-08-18 18:05  菜到不得鸟  阅读(339)  评论(0)    收藏  举报