/*
TASK:post
LANG:C++
*/

#include <cstdio>
#include <cassert>

const int MAXN = 1 << 11;
const int MAXM = 1 << 16;

struct el {
	int to;
	int next;
	el () {}
	el (int _to, int _next) : to (_to), next (_next) {}
};

int N, M;
int vec[MAXN], rvec[MAXN], V[MAXN];
el buf[MAXM], rbuf[MAXM], B[MAXN];
int Bp;

int used[MAXN];

int por[MAXN], pp;
int gc;
int gs[MAXN];
int inc;

bool added[MAXN][MAXN];

void dfs2 (int a) {
//	printf ("%d (%d)\n", a, gc);
	used[a] = gc;
	++inc;
	for (int i = rvec[a]; i != -1; i = rbuf[i].next)
		if (used[rbuf[i].to] == -1) dfs2 (rbuf[i].to);
}

void dfs1 (int a) {
	for (int i = vec[a]; i != -1; i = buf[i].next)
		if (!used[buf[i].to]) {
			used[buf[i].to] = -1;
			dfs1 (buf[i].to);
		}
	por[pp++] = a;
}

int ts[MAXN];
int tco[MAXN], tcp;

void topsort (int a) {
	used[a] = -2;
	for (int i = V[a]; i != -1; i = B[i].next)
		if (used[B[i].to] > 0) topsort (B[i].to);
	tco[tcp++] = a;
	ts[a] = tcp - 1;
}

int dp[MAXN][MAXN];

int dpr (int a, int b) {
	if (a > b) a ^= b ^= a ^= b;
//	printf ("%d %d\n", a, b);
	if (dp[a][b] != -1) return dp[a][b];

	if (ts[a] > ts[b]) {//move a
		for (int i = V[a]; i != -1; i = B[i].next)
			dp[a][b] >?= dpr (B[i].to, b);
		dp[a][b] += gs[a];
	} else {//move b
		for (int i = V[b]; i != -1; i = B[i].next)
			dp[a][b] >?= dpr (a,  B[i].to);
		dp[a][b] += gs[b];
	}

	if (a == b) dp[a][b] -= gs[a];
//	printf ("<-- %d %d(%d)\n", a, b, dp[a][b]);
	return dp[a][b];
}

int main () {
//	printf ("xx!\n");
	scanf ("%d %d", &N, &M);
	int i;
	int a, b;
	for (i = 0; i < N; ++i) vec[i] = rvec[i] = -1;
	for (i = 0; i < M; ++i) {
		scanf ("%d %d", &a, &b);
		--a; --b;
		buf[i] = el (b, vec[a]);
		vec[a] = i;
		rbuf[i] = el (a, rvec[b]);
		rvec[b] = i;
	}
//	printf ("yohoho!\n");

	used[0] = -1;
	dfs1 (0);
//	for (i = 0; i < pp; ++i) printf ("%d(%d) ", por[i]); printf ("\n");
	

	assert (pp == N);
	for (i = pp-1; i >= 0; --i) {
		if (used[por[i]] == -1) {
			dfs2 (por[i]);
			gs[gc++] = inc;
//			printf ("--%d\n", inc);
			inc = 0;
		}
	}

//	for (i = 0; i < N; ++i) printf ("%d ", used[i]); printf ("\n");
	int j;
	for (i = 0; i <= gc; ++i) {added[i][i] = 1; V[i] = -1;}
	for (i = 0; i < N; ++i)
		for (j = vec[i]; j != -1; j = buf[j].next) {
//			printf ("try %d %d (%d %d)\n", i, buf[j].to, used[i], used[buf[j].to]);
			if (!added[used[i]][used[buf[j].to]]) {
				added[used[i]][used[buf[j].to]] =
				added[used[buf[j].to]][used[i]] = 1;
				B[Bp] = el (used[buf[j].to], V[used[i]]);
				V[used[i]] = Bp++;
//				printf ("add %d %d\n", i, buf[j].to);
			}
		}
	for (i = 0; i < gc; ++i)
		if (V[i] == -1) {
			B[Bp] = el (gc, V[i]);
			V[i] = Bp++;
		}
	for (i = 0; i <= gc; ++i)
		for (j = i; j <= gc; ++j)
			dp[i][j] = -1;
	dp[gc][gc] = 0;
	gs[gc] = 0;
	++gc;
/*
	for (i = 0; i < gc; ++i) {
		printf ("%d(%d) ->", i, gs[i]);
		for (j = V[i]; j != -1; j = B[j].next)
			printf (" %d", B[j].to);
		printf ("\n");
	}
*/
	topsort (0);
	assert (tcp == gc);
//	for (i = 0; i < tcp; ++i) printf ("%d ", ts[i]); printf ("\n");
	dpr (0, 0);
	printf ("%d\n", dp[0][0]);

	return 0;
}
