https://www.luogu.org/problem/P2863

#include<cstdio>
#include<vector>
using namespace std;
int dfn[10005],low[10005],stack[10005],scc[10005],num[10005],vis[10005];
int clock,scc_cnt,top;
vector<int>e[10005];
inline void dfs_scc(int x)
{
    dfn[x]=low[x]=++clock;//访问次序标记;x能到的祖先中节点编号最小的 
    stack[++top]=x;//把走过的节点入栈 
    vis[x]=1;
    for(int i=0;i<e[x].size();i++)
    {
        int now=e[x][i];
        if(!dfn[now])//如果没有被访问过 
        {
            dfs_scc(now);//进它 
            low[x]=min(low[x],low[now]);//既然now是x的子节点,那么他们一定有公告的祖先,取个小的 
        } 
        else
        if(vis[now])//如果他还没有被其他强连通分量使用 
        low[x]=min(low[x],dfn[now]);//那么再小一点 
    }
    if(low[x]==dfn[x])
    {
        scc_cnt++;
        while(stack[top]!=x)
        {
        //x节点在栈中夹着的节点就是强连通分量的节点 
            scc[stack[top--]]=scc_cnt;
            vis[stack[top+1]]=0;
            num[scc_cnt]++;
        }//哪一个点在当前编号为scc_cnt的强连通分量里 
        top--;
        vis[x]=0;
        num[scc_cnt]++;
        scc[x]=scc_cnt;//一个强连通分量 
    } 
} 
int main()
{
    int n,m,a,b;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        e[a].push_back(b);
        //e[b].push_back(a);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==0)
        {
            dfs_scc(i);
        }
    }
    for(int i=1;i<=scc_cnt;i++)
    {
        if(num[i]>1)
        {
            ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}