AcWing 1174. 受欢迎的牛
求强连通分量的tarjan算法要记住
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10, M = 5e4 + 10;
int h[N], e[M], ne[M], idx;
int n, m;
int stk[N], top; //栈
bool is_stk[N]; //标记这个点是否在栈内
int id[N]; //记录点在哪个连通分量内
int dfn[N]; //记录这个点自个儿的时间戳
int low[N]; //记录这个点能到达的最小的时间戳
int timep; //时间戳
int scc_cnt; //记录强连通分量的数量
int Size[N]; //记录连通分量内部点的数量
int dcout[N]; //记录连通分量的出度
int ans; //记录答案
int ni; //记录符合条件的强连通分量的数量,如果大于1则题中所求量为0
void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++ ;
}
void tarjan(int u){ //遍历u所在的连通分量
low[u] = dfn[u] = ++ timep;
stk[ ++ top] = u;
is_stk[u] = true;
for(int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if(!dfn[j]){ //如果这个点还没被搜索过
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if(is_stk[j]) low[u] = min(low[u], dfn[j]);
}
if(low[u] == dfn[u]){
int y;
++ scc_cnt;
do{
y = stk[top -- ];
is_stk[y] = false;
id[y] = scc_cnt;
Size[scc_cnt] ++ ;
}while(y != u);
}
}
int main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
for(int i = 0; i < m; i ++ ){
int a, b;
cin>>a>>b;
add(a, b);
}
for(int i = 1; i <= n; i ++ ){
if(!dfn[i]){ //如果这个点还没被tarjan过
tarjan(i);
}
}
for(int i = 1; i <= n; i ++ ){
for(int j = h[i]; ~j; j = ne[j]){
int k = e[j];
int a = id[i], b = id[k]; //i才是节点
if(a != b) dcout[a] ++ ;
}
}
for(int i = 1; i <= scc_cnt; i ++ ){ //遍历所有强连通分量
if(!dcout[i]){ //如果这个强连通分量的出度为0
ni ++ ;
ans += Size[i];
if(ni > 1){
ans = 0;
break;
}
}
}
cout<<ans<<endl;
return 0;
}