poj 3352 双连通分量

至少加几条边成为双连通分量

 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=10000;
struct
{
    int to,next;
}e[maxn];
int head[maxn],lon;
int dfn[maxn],instack[maxn],low[maxn],stack[maxn],s[maxn];
int in[maxn];
int count,top,con;
int n,m;
void edgemake(int from,int to,int head[])
{
    e[++lon].to=to;
    e[lon].next=head[from];
    head[from]=lon;
}
void edgeini()
{
    memset(head,-1,sizeof(head));
    lon=-1;
}

void tarjan(int t,int from)
{
    dfn[t]=low[t]=++count;
    instack[t]=1;
    stack[++top]=t;
    for(int k=head[t];k!=-1;k=e[k].next)
    {
        if(k==(from^1)) continue;
        int u=e[k].to;
        if(dfn[u]==-1)
        {
            tarjan(u,k);
            low[t]=min(low[t],low[u]);
        }
        else if(instack[u])
        {
            low[t]=min(low[t],dfn[u]);
        }
    }
    if(dfn[t]==low[t])
    {
        ++con;
        while(1)
        {
            int u=stack[top--];
            instack[u]=0;
            s[u]=con;
            if(u==t) break;
        }
    }
}

void tarjan()//tarjan的初始化
{
    memset(dfn,-1,sizeof(dfn));
    memset(instack,0,sizeof(instack));
    count=top=con=0;
    for(int i=1;i<=n;i++)
    if(dfn[i]==-1)
    tarjan(i,-1);
}

int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        edgeini();
        for(int i=1,from,to;i<=m;i++)
        {
            scanf("%d %d",&from,&to);
            edgemake(from,to,head);
            edgemake(to,from,head);
        }
        tarjan();
        memset(in,0,sizeof(in));
        for(int i=1;i<=n;i++)
        for(int k=head[i];k!=-1;k=e[k].next)
        if(s[i]!=s[e[k].to])
        {
            in[s[i]]++;
        }
        int ans=0;
        for(int i=1;i<=con;i++)
        if(in[i]==1)
        ans++;
        else if(in[i]==0)
        ans+=2;
        if(con==1) ans-=2;
        printf("%d\n",(ans+1)/2);
    }
    return 0;
}


 

 

posted @ 2013-08-19 19:24  pangbangb  阅读(207)  评论(0编辑  收藏  举报