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

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, const pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}


const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

struct Edge{
  int to, cost;

  Edge(int t, int c = 0): to(t), cost(c)
  {}
  bool operator>(const Edge& rhs) const{
	return cost > rhs.cost;
  }
  bool operator<(const Edge& rhs) const{
	return cost < rhs.cost;
  }

};
using Graph = vector<vector<Edge>>;
void add_edge(Graph& graph, int u, int v, int cost = 0){
  graph[u].push_back(Edge(v,cost));
}

void SCC(const Graph& g,
		 vector< vector<int> >& scc) {
  const int n = g.size();
  vector<int> num(n), low(n);
  stack<int> S;
  vector<bool> inS(n);
  int time = 0;

  function<void(int)> visit = [&](int v){
	low[v] = num[v] = ++time;
	S.push(v); inS[v] = true;
	for(auto& e: g[v]) {
	  int w = e.to;
	  if (num[w] == 0) {
		visit(w);
		low[v] = min(low[v], low[w]);
	  } else if (inS[w])
		low[v] = min(low[v], num[w]);
	}
	if (low[v] == num[v]) {
	  scc.push_back(vector<int>());
	  while (1) {
		int w = S.top(); S.pop(); inS[w] = false;
		scc.back().push_back(w);
		if (v == w) break;
	  }
	}
  };

  for(int u=0;u<n;++u)
	if(num[u] == 0)
	  visit(u);
}
void makeDAG(int V,
			 const Graph& G,
			 const vector< vector<int> >& scc,
			 vector<int>& member,
			 Graph& dag){
  int M = SZ(scc);
  member.resize(V);
  for(int i=0;i<M;++i)
	for(int v: scc[i])
	  member[v] = i;

  vector<set<int>> s(M);
  for(int i=0;i<V;++i){
	for(auto&& e: G[i])
	  if(member[i] != member[e.to])
		s[member[i]].insert(member[e.to]);
  }
  dag.resize(M);
  for(int i=0;i<M;++i){
	dag[i] = vector<Edge>(begin(s[i]), end(s[i]));
  }
}

bool topo_sort(const Graph& G, VI& order){
  int N = G.size();
  VI color(N, 0);
  
  function<bool(int)> visit = [&](int v)->bool{
	color[v] = 1;
	for(const auto& e: G[v]){
	  if(color[e.to] == 2) continue;
	  if(color[e.to] == 1) return false;
	  if(!visit(e.to)) return false;
	}
	order.push_back(v);
	color[v] = 2;
	return true;
  };

  for(int u=0;u<N;++u)
	if(!color[u] && !visit(u))
	  return false;
  reverse(begin(order), end(order));
  return true;
}
 
int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N, M;
  cin >> N >> M;
  Graph G(N);
  REP(i,M){
	int u, v;
	cin >> u >> v;
	add_edge(G, u, v);
  }

  if(N == 1 && M == 0){
	cout << 0 << endl;
	return 0;
  }
  if(N >= 2 && M == 0){
	cout << N << endl;
	return 0;
  }

  VVI scc;
  SCC(G, scc);
  VI mem;
  Graph dag;
  makeDAG(N, G, scc, mem, dag);

  M = SZ(dag);
  if(M == 1){
	cout << 0 << endl;
	return 0;
  }

  VI in(M);
  REP(i,M)
	for(auto& e: dag[i])
	  in[e.to]++;
  
  int nin = 0, nout = 0;
  REP(i,M){
	if(dag[i].empty()) nout++;
	if(!in[i]) nin++;
  }
  
  cout << max(nout, nin) << endl;

  return 0;
}

Measured memory_bytes: 10968