Fork me on GitHub

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

 

posted @ 2014-07-10 21:34  whatbeg  阅读(294)  评论(0编辑  收藏  举报