#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <stdlib.h>
#include <map>
#include <cmath>
#define MOD_P 1000000007
#define MOD_Q 998244353
#define PI 3.14159265358979
#define ll long long
using namespace std;


bool rec(int i, int w, vector<vector<int>> dp, vector<int> a) {
	if (i == 0) {
		if (w == 0) {
			return true;
		} else {
			return false;
		}
	}
	bool res = false;

	if (w >= a[i - 1] && rec(i - 1, w - a[i - 1], dp, a))res = true;
	if (rec(i - 1, w, dp, a))res = true;
	return dp[i][w] = res;

}


//int main() {
//	int n;
//	cin >> n;
//	vector<int> t(n);
//	int sum = 0;
//	int left, right;
//	for (int i = 0; i < n; i++) {
//		cin >> t[i];
//		sum += t[i];
//	}
//
//	left = (sum + 1) / 2;
//
//	right = sum;
//	int half;
//	while (left + 1 != right) {
//		half = (right + left) / 2;
//		printf("[%d %d %d]", left, right, half);
//		vector<vector<int>> dp(n + 1, vector<int>(half + 1, -1));
//		if (rec(n, half, dp, t)) {
//			printf("can\n");
//			right = half;
//		} else {
//			printf("can't\n");
//			left = half;
//		}
//	}
//
//
//
//	printf("%d", right);
//
//	return 0;
//}

int main() {
	int n, m, a, b;
	cin >> n >> m;
	vector<vector<int>>edge(n);
	for (int i = 0; i < m; i++) {
		cin >> a >> b;
		a--; 
		b--;
		edge[a].emplace_back(b);
	}

	vector<int>st;
	int now;
	int ans = n;
	for (int i = 0; i < n; i++) {
		vector<bool>first(n, true);
		st.push_back(i);
		first[i] = false;
		//printf("%d:", i + 1);
		while (!st.empty()) {
			now = st.back();
			st.pop_back();
			
			for (int v : edge[now]) {
				if (first[v]) {
					first[v] = false;
					//printf("%d ", v + 1);
					st.push_back(v);
					ans++;
				}
			}
		}
		//printf("\n");
	}

	printf("%d", ans);

}
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
#include <numeric>
#include <string>
#include <cstring>
#include <list>
#include <unordered_set>
#include <tuple>
#include <cmath>
#include <limits>
#include <type_traits>
#include <iomanip>
#include <map>
#include <unordered_map>
#include <queue>
#include <stack>
#include <set>
#include <bitset>
#include <regex>
#include <random>
#include<bits/stdc++.h>
//#include<atcoder/all>

using namespace std;
//using namespace atcoder;

typedef long long ll;
#define rep(i,n)for(ll i=0;i<n;++i)
#define exout(x) printf("%.12f\n", x)
const double pi = acos(-1.0);
const ll MOD = 1000000007;
const ll INF = 1e18;
const ll MAX_N = 1010101;

//組み合わせの余りを求める
ll fac[MAX_N], finv[MAX_N], inv[MAX_N];
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX_N; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
		finv[i] = finv[i - 1] * inv[i] % MOD;
	}
}

// 二項係数計算
long long COM(ll n, ll k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

// mod.m での a の逆元 a^ { -1 } を計算する
long long modinv(long long a, long long m) {
	long long b = m, u = 1, v = 0;
	while (b) {
		long long t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m;
	if (u < 0) u += m;
	return u;
}

//最大公約数
ll gcd(ll x, ll y) {
	return y ? gcd(y, x % y) : x;
}

ll lcm(ll x, ll y) {
	if (x == 0 || y == 0)return 0;
	return (x / gcd(x, y) * y);
}

//union-find木について
//サイズによる更新をしている
ll par[4010101];
ll rank2[4010101];

void init(ll n) {
	rep(i, n) {
		par[i] = i;
		rank2[i] = 1;
	}
}

ll find(ll x) {
	if (par[x] == x) {
		return x;
	}
	else {
		return par[x] = find(par[x]);
	}
}

void unite(ll x, ll y) {
	x = find(x);
	y = find(y);
	if (x == y)return;
	if (rank2[x] < rank2[y]) {
		par[x] = y;
		rank2[y] += rank2[x];
	}
	else {
		par[y] = x;
		rank2[x] += rank2[y];
	}
}

//セグ木
class segment_tree {
private:
	ll sz;
	std::vector<ll> seg;
	std::vector<ll> lazy;
	void push(ll k) {
		if (k < sz) {
			lazy[k * 2] = max(lazy[k * 2], lazy[k]);
			lazy[k * 2 + 1] = max(lazy[k * 2 + 1], lazy[k]);
		}
		seg[k] = max(seg[k], lazy[k]);
		lazy[k] = 0;
	}
	void update(ll a, ll b, ll x, ll k,ll l, ll r) {
		push(k);
		if (r <= a || b <= l) return;
		if (a <= l && r <= b) {
			lazy[k] = x;
			push(k);
			return;
		}
		update(a, b, x, k * 2, l, (l + r) >> 1);
		update(a, b, x, k * 2 + 1, (l + r) >> 1, r);
		seg[k] = max(seg[k * 2], seg[k * 2 + 1]);
	}
	ll range_max(ll a, ll b, ll k, ll l, ll r) {
		push(k);
		if (r <= a || b <= l) return 0;
		if (a <= l && r <= b) return seg[k];
		ll lc = range_max(a, b, k * 2, l, (l + r) >> 1);
		ll rc = range_max(a, b, k * 2 + 1, (l + r) >> 1, r);
		return max(lc, rc);
	}
public:
	segment_tree() : sz(0), seg(), lazy() {};
	segment_tree(ll N) {
		sz = 1;
		while (sz < N) {
			sz *= 2;
		}
		seg = std::vector<ll>(sz * 2, 0);
		lazy = std::vector<ll>(sz * 2, 0);
	}
	void update(ll l, ll r, ll x) {
		update(l, r, x, 1, 0, sz);
	}
	ll range_max(ll l, ll r) {
		return range_max(l, r, 1, 0, sz);
	}
};

ll dx[4] = { 1,-1,0,0 };
ll dy[4] = { 0,0,1,-1 };
ll a[1010][1010];
vector<vector<ll>>to;
bool flag[2020];
ll ans = 0;

void dfs(ll x) {
	ans++;
	flag[x] = true;
	for (auto nx : to[x]) {
		if (flag[nx] == false) {
			dfs(nx);
		}
	}
}

//long longしか使わない
//素数は1より大きい
//lower_boundは指定したkey以上の要素の一番左のイテレータをかえす
//upper_boundは指定したkeyより大きい要素の一番左のイテレータをかえす
int main() {
	ll n, m;
	cin >> n >> m;
	to.resize(n);
	rep(i, m) {
		ll x, y;
		cin >> x >> y;
		x--, y--;
		to[x].emplace_back(y);
	}
	rep(i, n) {
		dfs(i);
		rep(j, n) {
			flag[j] = false;
		}
	}
	cout << ans << endl;
	return 0;
}

