include<cstdio>
#define reg register
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define erep(i,G,x) for(int i=(G).Head[x];i;i=(G).Nxt[i])
char buf[200000],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,200000,stdin),p1==p2)?EOF:*p1++)
inline void Rd(int &res) {
res=0;
int flag=0;
char c;
while(c=getchar(),c<48||c>57)flag|=c=='-';
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c<=57&&c>=48);
res=flag?-res:res;
}
template<class T>inline bool Max(T &a,T b) {
return a<b?a=b,1:0;
}
template<class T>inline bool Min(T &a,T b) {
return a>b?a=b,1:0;
}
const int N=1e4+5,M=5e4+5;
bool MOP1;
struct Link_list {
int Tot,Head[N],to[M],Nxt[M];
inline void AddEdge(int a,int b) {
to[++Tot]=b,Nxt[Tot]=Head[a],Head[a]=Tot;
}
} G;
int a,b,dfn[N],low[N],stk[N],belong[N],Sz[N],Id,cnt,top;
bool Instack[N];
void dfs(int x) {
dfn[x]=low[x]=++cnt;
stk[++top]=x,Instack[x]=1;
erep(i,G,x) {
int y=G.to[i];
if(!dfn[y])dfs(y),Min(low[x],low[y]);
else if(Instack[y])Min(low[x],dfn[y]);
}
if(dfn[x]==low[x]) {
Id++;
int y;
do y=stk[top--],Sz[belong[y]=Id]++,Instack[y]=0;
while(y^x);
}
}
bool MOP2;
inline void _main(void) {
// cerr<<"M="<<(&MOP2-&MOP1)/1024.0/1024.0<<endl;
int n,m;
Rd(n),Rd(m);
rep(i,1,m)Rd(a),Rd(b),G.AddEdge(a,b);
rep(i,1,n)if(!dfn[i])dfs(i);
rep(i,1,n)stk[i]=0;
rep(i,1,n)erep(j,G,i)(belong[G.to[j]]^belong[i])&&(stk[belong[i]]=1);
int Ans=0;
rep(i,1,Id)if(!stk[i]) {
if(Ans)return (void)puts("0");
Ans=Sz[i];
}
printf("%d\n",Ans);
}
int main() {
// freopen(".in","r",stdin),freopen(".out","w",stdout);
_main();
// fclose(stdin),fclose(stdout);
}