题目大意:
n头牛,m个崇拜关系,并且崇拜具有传递性
如果a崇拜b,b崇拜c,则a崇拜c
求最后有几头牛被所有牛崇拜
强连通分量内任意两点都能互达 所以只要强联通分量内有一点是 那么其它点也都会是
按照崇拜关系 即a崇拜b就连一条a到b的边 tarjan求得所有强联通分量并染色
而把一个强联通分量缩成一个超级点后 整个图的崇拜关系就变成了一个 有向无环图
此时被所有牛崇拜的牛就是 一个出度为0的超级点
只要把所有边再走一遍就可以计算出度 同时计算每个超级点内有多少个点
即从a出发到b的边 若a b的颜色相同说明是在同一个超级点内那么点数+1 颜色不同那么a的出度+1
但当出现 多个出度为0的超级点 时 必然存在一个出度为0的超级点不被另一个出度为0的超级点崇拜
那么就不满足被所有牛崇拜这个条件 此时答案为 0
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std; const int N=;
struct EDGE { int to, nt; }e[*N];
int head[N], tot;
int dfn[N], low[N], ind;
int col[N], id;
bool vis[N];
stack <int> s; int n, m, cnt[N], du[N]; void init() {
while(!s.empty()) s.pop();
for(int i=;i<=n;i++) {
head[i]=dfn[i]=low[i]=col[i]=-;
vis[i]=cnt[i]=du[i]=;
}
tot=ind=id=;
}
void addE(int u,int v) {
e[tot].to=v;
e[tot].nt=head[u];
head[u]=tot++;
} void tarjan(int u) {
dfn[u]=low[u]=ind++;
s.push(u); vis[u]=;
for(int i=head[u];i!=-;i=e[i].nt) {
int v=e[i].to;
if(dfn[v]==-) {
tarjan(v);
low[u]=min(low[u],low[v]);
} else {
if(vis[v]) low[u]=min(low[u],low[v]);
}
}
if(dfn[u]==low[u]) {
col[u]=++id;
vis[u]=;
while(s.top()!=u) {
col[s.top()]=id;
vis[s.top()]=;
s.pop();
} s.pop();
}
} int main()
{
while(~scanf("%d%d",&n,&m)) {
init();
for(int i=;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
addE(u,v);
}
for(int i=;i<=n;i++)
if(dfn[i]==-) tarjan(i);
for(int i=;i<=n;i++) {
for(int j=head[i];j!=-;j=e[j].nt)
if(col[e[j].to]!=col[i])
du[col[i]]++;// 计算出度
cnt[col[i]]++;
}
int tmp=, ans;
for(int i=;i<=id;i++)
if(du[i]==) tmp++, ans=cnt[i];
if(tmp==) printf("%d\n",ans);
else printf("0\n");
} return ;
}