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;

}


 

 

你可能感兴趣的:(poj)