bzoj1051 [HAOI2006]受欢迎的牛 tarjan&&缩点

题目描述

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

输入格式:

第一行:两个用空格分开的整数:N和M

第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B 

输出格式:

第一行:单独一个整数,表示明星奶牛的数量

 

tarjan缩点以后重新建图,如果只有一个点没有出边,那么输出这个强联通分量的大小,否则就没有明星牛。

注意 tarjan缩点时记录每条边连着两点的数组应该开的和变数一样大,我开小就wa了一个点。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,cnt,head[10005],x[100005],y[100005];
int dfn[10005],low[10005],vis[10005],hav[10005],bel[10005],q[10005];
struct edge{
    int next,to;
}e[100005];
void insert(int u,int v){
    cnt++;
    e[cnt].next=head[u];e[cnt].to=v;
    head[u]=cnt;
}
int top,ind,k;
void tarjan(int x){
    q[++top]=x;
    dfn[x]=low[x]=++ind;
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int s=e[i].to;
        if(!dfn[s]){
            tarjan(s);
            low[x]=min(low[s],low[x]);
        }
        else if(vis[s]){
            low[x]=min(dfn[s],low[x]);
        }
    }
    int now=0;
    if(dfn[x]==low[x]){
        k++;
        while(now!=x){
            now=q[top];top--;
            vis[now]=0;
            bel[now]=k;
            hav[k]++;
        }
    }
}
int ans;
void work(){
    for(int i=1;i<=k;i++){
        if(!head[i]){
            if(ans){
                ans=0;
                return ;
            }
            else ans=hav[i];
        }
    }
}
int mx=0;
int main(){
    scanf("%d%d",&n,&m);
    int u,v,t;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x[i],&y[i]);
        insert(x[i],y[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }
    cnt=0;
    memset(head,0,sizeof head);
    memset(e,0,sizeof e);
    for(int i=1;i<=m;i++){
        if(bel[x[i]]!=bel[y[i]])insert(bel[x[i]],bel[y[i]]);
    } 
    work();
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-12-14 16:26  Elfish?  阅读(...)  评论(... 编辑 收藏