#include <bits/stdc++.h>
namespace ztd {
using namespace std;
template <typename T>
inline void read(T& t) {
  t = 0;
  short f = 1;
  char ch = getchar();
  double d = 0.1;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -f;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') t = t * 10 + ch - '0', ch = getchar();
  if (ch == '.') {
    ch = getchar();
    while (ch <= '9' && ch >= '0') t += d * (ch ^ 48), d *= 0.1, ch = getchar();
  }
  t *= f;
}
inline long long ksm(long long x, int y) {
  long long ret = 1;
  while (y) {
    if (y & 1) ret = ret * x % 2147483647;
    y >>= 1;
    x = x * x % 2147483647;
  }
  return ret;
}
inline long long inv(long long x) { return ksm(x, 2147483647 - 2); }
}  // namespace ztd
using namespace ztd;
const long long maxn = 20;
long long n, m;
long long last[maxn], ecnt;
struct edge {
  long long y, gg;
} e[3005];
inline void addedge(long long x, long long y) {
  e[++ecnt].y = y;
  e[ecnt].gg = last[x];
  last[x] = ecnt;
}
long long f[1 << maxn][maxn];
bool vis[maxn];
long long dfs(long long start, long long x, long long stat) {
  vis[x] = 1;
  if (f[stat][x]) return f[stat][x];
  for (long long i = last[x]; i; i = e[i].gg) {
    long long y = e[i].y;
    if ((1 << (y - 1)) & stat) {
      if (__builtin_popcountll(stat) > 2 && y == start) {
        ++f[stat][x];
      }
    } else {
      if (y > start) {
        f[stat][x] += dfs(start, y, stat | (1 << (y - 1)));
      }
    }
  }
  return f[stat][x];
}
signed main() {
  read(n);
  read(m);
  long long xx, yy;
  for (long long i = 1; i <= m; ++i) {
    read(xx);
    read(yy);
    addedge(xx, yy);
    addedge(yy, xx);
  }
  long long ans = 0;
  for (long long i = 1; i <= n; ++i) {
    ans += dfs(i, i, 1 << (i - 1));
  }
  printf("%lld\n", ans / 2);
  return 0;
}
