POJ3177 求边双连通分量

多了就不吐槽了,也是我过于相信同学,最开始没有计算重边(一位AK大神不计算重边就AC了)和没有建双向边(另一个大神说建单向边就过了,觉得这个最假)。思路还是用tarjan算法,找出边的双连通分量,缩点,然后答案就是(叶子节点数+1)/2.

感觉自己对tarjan的理解还不够,希望批评指正。

#include
#include
#include
#include
#include
#include

using namespace std;

const int MAXV =5005;
stack<int> st;
vector<int> E[MAXV];
int in[MAXV];
bool inst[MAXV];

int TJ = 0;
int belong[MAXV];
int dfn[MAXV];
int low[MAXV];
int num = 0;

void tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++num;
    st.push(u);
    inst[u] = true;
    vector<int>::iterator it;
    for(it = E[u].begin();it!=E[u].end();it++)
    {
        if(*it == fa) continue; //判断是否搜重
        int v = *it;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
        }
        else if(inst[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(dfn[u] == low[u])
    {
        TJ++;
        int v;
        do
        {
            v = st.top();
            st.pop();
            inst[v] = false;
            belong[v] = TJ;
        }while(u!=v);
    }
}

int N,M;
bool used[MAXV][MAXV];

int main()
{
    scanf("%d %d",&N,&M);
    for(int i=1;i<=M;i++)
    {
        int a, b;
        scanf("%d %d",&a,&b);
        if(used[a][b]) continue; //防止搜重边
        used[a][b] = used[b][a]  = true;
        E[a].push_back(b);
        E[b].push_back(a);
    }
    tarjan(1,0); //图是强连通分量,进行一次tarjan
    vector<int>::iterator it;
    for(int i=1;i<=N;i++)
        for(it=E[i].begin();it!=E[i].end();it++)
        {
            if(belong[i] != belong[*it])
            {
                in[belong[*it]]++;
            }
        }
    int res2 = 0;
    for(int i=1;i<=TJ;i++) if(in[i] == 1) res2++;
    printf("%d\n",(res2+1)/2);
    return 0;
}

你可能感兴趣的:(图论,poj,图论)