POJ 2186 Popular Cows --强连通分量

题意:给定一个有向图,问有多少个点由任意顶点出发都能达到。

分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0。

先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样,这个有向图就变成了一个有向无环图。

在这个新的图中,只需知道出度为0的点有几个即可。

如果出度为0的点超过1个,则输出0;否则输出出度为0的点所代表的那个强连通分支的分量数即可。

用Tarjan求强连通分量

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <cstdlib>

#include <algorithm>

#include <string>

#include <vector>

#include <stack>

using namespace std;

#define N 10007



vector<int> G[N],G2[N];

stack<int> stk;

int instk[N],cnt,Time,n,m,out[N];

int low[N],dfn[N],bel[N],num[N];



void tarjan(int u)

{

    low[u] = dfn[u] = ++Time;

    stk.push(u);

    instk[u] = 1;

    for(int i=0;i<G[u].size();i++)

    {

        int v = G[u][i];

        if(!dfn[v])

        {

            tarjan(v);

            low[u] = min(low[u],low[v]);

        }

        else if(instk[v])

            low[u] = min(low[u],dfn[v]);

    }

    if(low[u] == dfn[u])

    {

        cnt++;

        int v;

        do

        {

            v = stk.top();

            stk.pop();

            instk[v] = 0;

            bel[v] = cnt;

            num[cnt]++;

        }while(u != v);

    }

}



void Tarjan()

{

    memset(bel,0,sizeof(bel));

    memset(low,0,sizeof(low));

    memset(dfn,0,sizeof(dfn));

    memset(instk,0,sizeof(instk));

    memset(num,0,sizeof(num));

    memset(out,0,sizeof(out));

    while(!stk.empty())

        stk.pop();

    Time = cnt = 0;

    for(int i=1;i<=n;i++)

        if(!dfn[i])

            tarjan(i);

}



void Build()

{

    int i,j;

    for(i=0;i<=cnt;i++)

        G2[i].clear();

    for(i=1;i<=n;i++)

    {

        for(j=0;j<G[i].size();j++)

        {

            int v = G[i][j];

            if(bel[i] != bel[v])

            {

                G2[bel[i]].push_back(bel[v]);

                out[bel[i]]++;

            }

        }

    }

}



int main()

{

    int i,j,u,v;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i=0;i<=n;i++)

            G[i].clear();

        for(i=0;i<m;i++)

        {

            scanf("%d%d",&u,&v);

            G[u].push_back(v);

        }

        Tarjan();

        Build();

        int ans = 0;

        int flag = 0;

        int tag = 1;

        for(i=1;i<=cnt;i++)

        {

            if(out[i])

                continue;

            if(flag)

            {

                tag = 0;

                break;

            }

            else

            {

                ans += num[i];

                flag = 1;

            }

        }

        if(!tag)

            puts("0");

        else

            printf("%d\n",ans);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(poj)