#include <bits/stdc++.h>
using namespace std;

const int N=10005;
const int M=50005;
int n, m, E=0, scc_cnt=0;
int head[N], id[N], sz[N], dout[N];
int dfn[N], low[N], ts=0; // tarjan相关数组, dfn为时间戳数组, low为子树能够回溯到最早栈中节点的dfn值
stack<int> st; // tarjan 辅助栈
bool vis[N]; // 记录点是否在栈中


struct Edge{int v, ne;}e[M];
inline void add(int a, int b){
    e[E].v=b;
    e[E].ne=head[a];
    head[a]=E++;
}


void tarjan(int u){ // tarjan scc
    dfn[u]=low[u]=++ts;
    st.push(u); vis[u]=true;
    // 对u点的邻点进行tarjan递归
    for(int i=head[u]; ~i; i=e[i].ne){
        int v=e[i].v;
        if(!dfn[v]){ // 如果节点v未被访问, (u, v)为树枝边
            tarjan(v);
            low[u]=min(low[u], low[v]);
        }
        else if(vis[v]){ // 如果节点被访问, (u, v)为后向边或者横叉边
            low[u]=min(low[u], dfn[v]);
        }
    }
    if(low[u]==dfn[u]){ // 如果当前点是可以回溯到的最早点, 即scc的起点
        ++scc_cnt;
        int j;
        do{
            j=st.top(); st.pop(); vis[j]=false; id[j]=scc_cnt; sz[scc_cnt]++;
        }while(j!=u);
    }
}


int main(){
    memset(vis, 0x00, sizeof vis);
    memset(id, 0x00, sizeof id);
    memset(sz, 0x00, sizeof sz);
    memset(dout, 0x00, sizeof dout);
    memset(head, -1, sizeof head);
    memset(dfn, 0x00, sizeof dfn);

    cin>>n>>m;
    for(int i=0; i<m; ++i){
        int a, b;
        cin>>a>>b;
        add(a, b);
    }

    for(int i=1; i<=n; ++i){ // 对每个未访问的点做一次tarjan,找出所有的scc
        if(!dfn[i]) tarjan(i);
    }

    // 缩点统计出度
    for(int i=1; i<=n; ++i){
        for(int j=head[i]; ~j; j=e[j].ne){
            int v=e[j].v;
            int a=id[i], b=id[v];
            if(a!=b) dout[a]++; // 如果a和b不是一个scc, a的出度加1, 将scc a缩点处理
        }
    }

    int cz=0, sum=0;
    for(int i=1; i<=scc_cnt; ++i){
        if(!dout[i]){
            cz++; sum+=sz[i];
            if(cz>1){sum=0; break;}
        }
    }
    cout<<sum<<endl;

    return 0;
}