【poj2186】 Popular Cows

http://poj.org/problem?id=2186 (题目链接)

题意

  给出一个n个点m条边的有向图,求其中没有出度强连通分量所包含的点有几个

Solution 

  其实这道题的题解已经在“题意”中给出了= =,先Tarjan跑出强连通分量,之后模拟给缩点后的图连边(其实并不用真的连边),来统计缩点后每个节点的出度。输出出度为0的强连通分量所包含的点即可,若有多个强连通分量出度为0,输出0(不要问我为什么,有时候事情就是这么不讲道理)。

代码

// poj2186
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<set>
#define MOD 1000000007
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
    LL x=0,f=1;char ch=getchar();
    while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

const int maxn=50010;
struct edge {int to,next;}e[maxn<<2];
int f[maxn],dfn[maxn],low[maxn],head[maxn],s[maxn],pos[maxn],cnts[maxn];
int ind,cnt,n,m,top,tot;

void insert(int u,int v) {
    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
}
void Tarjan(int u) {
    dfn[u]=low[u]=++ind;
    s[++top]=u;
    f[u]=1;
    for (int i=head[u];i;i=e[i].next) {
        if (!dfn[e[i].to]) {
            Tarjan(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
        }
        else if (f[e[i].to]) low[u]=min(low[u],dfn[e[i].to]);
    }
    if (dfn[u]==low[u]) {
        tot++;int j;
        do {
            j=s[top--];
            pos[j]=tot;
            cnts[tot]++;
            f[j]=0;
        }while (j!=u);
    }
}
int main() {
    while (scanf("%d%d",&n,&m)!=EOF) {
        top=0;cnt=0;ind=0;tot=0;
        for (int i=1;i<=n;i++) dfn[i]=low[i]=head[i]=cnts[i]=pos[i]=0;
        for (int i=1;i<=m;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            insert(x,y);
        }
        for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
        cnt=0;for (int i=1;i<=n;i++) f[i]=0;
        for (int i=1;i<=n;i++)
            for (int j=head[i];j;j=e[j].next)
                if (pos[i]!=pos[e[j].to]) f[pos[i]]++;
        int ans=0;
        for (int i=1;i<=tot;i++) if (!f[i]) ans++;
        if (ans>1) printf("0\n");
        else {
            ans=0;
            for (int i=1;i<=tot;i++) if (!f[i]) ans+=cnts[i];
            printf("%d\n",ans);
        }
    }
    return 0;
}

  

posted @ 2016-09-27 21:06  MashiroSky  阅读(243)  评论(0编辑  收藏  举报