//記憶話搜索方法
//此題狀態壓縮中套用記憶化搜索的方法
//並用樹狀數組的方法遍歷子集
# include<iostream>
# include<cstdio>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;
int n, m, dp[12][1 << 12], st[12], p[1 << 12];
int DP(int u, int s)
{
if (dp[u][s])
return dp[u][s];
if (!s)
return dp[u][s] = st[u] & 1;
int rest = s&st[u];
while (rest) {
int tp = rest&(-rest);
dp[u][s] += DP(p[tp], s - tp);
rest -= tp;
}
return dp[u][s];
}
int main()
{
int a, b;
while (~scanf("%d%d", &n, &m))
{
memset(st, 0, sizeof(st));
while (m--)
{
scanf("%d%d", &a, &b);
st[a - 1] |= (1 << (b - 1));
}
for (int i = 0; i<n; ++i)
p[1 << i] = i;
memset(dp, 0, sizeof(dp));
printf("%d\n", DP(0, (1 << n) - 2));
}
return 0;
}