bzoj 1051

如果A认为B是受欢迎的,B认为C是受欢迎的,C认为A是受欢迎的,这时形成了一个环。

这时如果A认为D是受欢迎的,那么B和C也认为D是受欢迎的。

于是要考虑缩点。为了好打邻接表用了vector代替。推荐用Tarjan或者Gabow算法。

缩点完最终只有可能有一个强连通分量的牛被全部牛认为是受欢迎的,或者直接没有。

如果有超过一个的强连通分量的出度为0那么没有牛被全部牛认为是受欢迎的。

否则就直接输出那个出度为0的强连通分量中牛的个数。

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=10001;
const int maxm=50001;
int read(){
    char c; while(!isdigit(c=getchar())); int x=c-'0';
    while(isdigit(c=getchar())) x=x*10+c-'0'; return x;
}
vector<int> e[maxn];
int top,cnt,tme,vis[maxn],low[maxn],dfn[maxn],sta[maxn],num[maxn],dis[maxn],peo[maxn];
void tarjan(int o){
    low[o]=vis[sta[++top]=o]=++tme;
    for(int i=0;i<e[o].size();i+=1)
        if(!dfn[e[o][i]]){
            if(!vis[e[o][i]]) tarjan(e[o][i]);
            low[o]=min(low[e[o][i]],low[o]);
        }
    if(vis[o]==low[o]){
        ++cnt;
        while(dfn[sta[top]]=cnt,peo[cnt]+=1,sta[top--]!=o);
    }
}
int main(){
    int n=read(),m=read(),ans=0;
    while(m--){
        int a=read(),b=read();
        e[a].push_back(b);
    }
    for(int i=1;i<=n;i+=1) if(!dfn[i]) tarjan(i);
    int tot=0,pre=0;
    for(int i=1;i<=n;i+=1)
        for(int j=0;j<e[i].size();j+=1)
            if(dfn[i]!=dfn[e[i][j]]) dis[dfn[i]]=1;
    for(int i=1;i<=cnt;i+=1) if(!dis[i]) tot+=1,pre=i;
    if(tot==1) printf("%d",peo[pre]); else printf("0");
    return 0;
}
原文地址:https://www.cnblogs.com/AmnesiacVisitor/p/7657623.html