边双联通分量

Posted lmjer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了边双联通分量相关的知识,希望对你有一定的参考价值。

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define maxn 1005
#define maxm 1000005

using namespace std;

struct Edge{
    int u,v;
    Edge(int u=0,int v=0):u(u),v(v){}
}e[maxm];
int n,m,stamp,dfn[maxn],low[maxn],bccno[maxn],bcc_cnt;
vector<int> vec[maxn];
bool isbridge[maxm];

void tarjan(int index,int fa)
{
    int tmp;
    dfn[index]=low[index]=++stamp;
    for(int i=0;i<vec[index].size();i++)
    {
        tmp=e[vec[index][i]].v;
        if(!dfn[tmp])
        {
            tarjan(tmp,index);
            low[index]=min(low[index],low[tmp]);
            if(low[tmp]>dfn[index])
                isbridge[vec[index][i]]=isbridge[vec[index][i]^1]=1;
        }
        else if(dfn[tmp]<dfn[index] && tmp!=fa)
        {
            low[index]=min(low[index], dfn[tmp]);
        }
    }
}

void dfs(int index)
{
    dfn[index]=1;
    bccno[index]=bcc_cnt;
    for(int i=0;i<vec[index].size();i++)
    {
        int tmp=vec[index][i];
        if(isbridge[tmp])
            continue;
        if(!dfn[e[tmp].v])
        {
            dfs(e[tmp].v);
        }
    }
}

void find_ebcc(){
    bcc_cnt=stamp=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(bccno,0,sizeof(bccno));
    memset(isbridge,0,sizeof(isbridge));
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i, -1);
    memset(dfn,0,sizeof(dfn));
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        {
            bcc_cnt++;
            dfs(i);
        }
    }               
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        memset(vec,0,sizeof(vec));
        int x,y;
        for(int i=0;i<m;i++)
        {
            scanf("%d %d",&x,&y);
            e[i*2]=Edge(x,y);
            vec[x].push_back(2*i);
            e[i*2+1]=Edge(y,x);
            vec[y].push_back(2*i+1);
        }
        find_ebcc();

        if(bcc_cnt==1)
            printf("0\n");
        else
        {
            memset(dfn,0,sizeof(dfn));
            for(int i=0;i<m*2;i+=2)
            {
                x=e[i].u, y=e[i].v;
                if(bccno[x]!=bccno[y])
                {
                    dfn[bccno[x]]++;
                    dfn[bccno[y]]++;
                }
            }

            int a=0,b=0;
            for(int i=1;i<=bcc_cnt;i++)
            {
                if(dfn[i]==0)
                    a++;
                if(dfn[i]==1)
                    b++;
            }

            printf("%d\n",a+(b+1)/2);           
        }
    }

    return 0;
}

以上是关于边双联通分量的主要内容,如果未能解决你的问题,请参考以下文章

边双联通分量

POJ 1515 双联通分量

双联通的tarjan算法

POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

边双联通分量

poj-3177(并查集+双联通分量+Tarjan算法)