#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
const int N = 20;
const int M = 1 << N;

int st[M], one[M];
int n, link[N];

long long d[N][M];

void deal(int idx, int num, int stid, int s) {
    if (idx == n + 1) {
        st[s] = stid;
        one[s] = num;
        return ;
    }
    if (stid == -1)
        deal(idx + 1, num + 1, idx, s | (1 << idx));
    else
        deal(idx + 1, num + 1, stid, s | (1 << idx));
    deal(idx + 1, num, stid, s);
}

long long dp(int u, int s) {
    if (d[u][s] >= 0)
        return d[u][s];

    if (one[s] == 1 || one[s] == 2)
        return d[u][s] = 1;

    d[u][s] = 0;
    int pre = s ^ (1 << u);
    for (int i = 0; i < n; ++i)
        if (i != st[pre] && (pre >> i & 1) && (link[i] >> u & 1)) {
            d[u][s] += dp(i, pre);
        }
    return d[u][s];
}

int main() {
    int m, u, v;
    scanf("%d", &n);
    scanf("%d", &m);
    while (m -- > 0) {
        scanf("%d%d", &u, &v);
        -- u;
        -- v;
        link[u] |= 1 << v;
        link[v] |= 1 << u;
    }

    deal(0, 0, -1, 0);

    memset(d, -1, sizeof d);
    int mx = (1 << n) - 1;
    long long ans = 0;
    for (int i = 0; i <= mx; ++i)
        if (one[i] > 2)
            for (int j = 0; j < n; ++j) {
                if (j == st[i])
                    continue;
                if ((i >> j & 1) && (link[j] >> st[i] & 1))
                    ans += dp(j, i);
            }

    printf("%I64d\n", ans / 2);
    return 0;
}


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

long long dp[(1 << 20) + 5][25];
int n, m, E[25][25];

int first_bit(int num)
{
  if(num == 0)
    return 21;
  for(int i=0; i<21; i++) {
    if(num & (1 << i))  {
      return i;
    }
  }
}

long long f(int mask, int last)
{
  int cnt = __builtin_popcount(mask), first = first_bit(mask), newmask = mask ^ (1 << last);
  if(cnt == 1)  {
    return (first == last) ? 1 : 0;
  }
  if(((mask & (1 << last)) == 0) || (first == last))  {
    return 0;
  }
  if(dp[mask][last] != -1) {
    return dp[mask][last];
  }

  long long ans = 0;
  for(int i = first; i<n; i++)  {
    if(E[last][i] and (mask & (1 << i)))  {
      ans += f(newmask, i);
    }
  }
  return dp[mask][last] = ans;
}

int main()
{
  ios::sync_with_stdio(false);
  cin >> n >> m;
  for(int i=0; i<(1 << n+1); i++) {
    for(int j=0; j<n+1; j++)  {
      dp[i][j] = -1;
    }
  }
  for(int i=0; i<25; i++) {
    for(int j=0; j<25; j++) {
      E[i][j] = 0;
    }
  }
  for(int i=0, a, b; i<m; i++)  {
    cin >> a >> b;
    --a; --b;
    E[a][b] = 1;
    E[b][a] = 1;
  }
  long long ans = 0;
  for(int mask=0; mask<(1 << n); mask++)  {
    int first = first_bit(mask), cnt = __builtin_popcount(mask);
    for(int last = 0; last < n; last++) {
      if(E[last][first] and ((1 << last) & mask) and (cnt > 2))  {
        ans += f(mask, last);
      }
    }
  }

  cout << ans / 2 << "\n";
}


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

long long dp[(1 << 20) + 5][25];
int n, m, E[25][25];

int first_bit(int num)
{
  if(num == 0)
    return 21;
  for(int i=0; i<21; i++) {
    if(num & (1 << i))  {
      return i;
    }
  }
}

long long f(int mask, int last)
{
  int cnt = bit_count(mask), first = first_bit(mask), newmask = mask ^ (1 << last);
  if(cnt == 1)  {
    return (first == last) ? 1 : 0;
  }
  if(((mask & (1 << last)) == 0) || (first == last))  {
    return 0;
  }
  if(dp[mask][last] != -1) {
    return dp[mask][last];
  }

  long long ans = 0;
  for(int i = first; i<n; i++)  {
    if(E[last][i] and (mask & (1 << i)))  {
      ans += f(newmask, i);
    }
  }
  return dp[mask][last] = ans;
}

int main()
{
  ios::sync_with_stdio(false);
  cin >> n >> m;
  for(int i=0; i<(1 << n+1); i++) {
    for(int j=0; j<n+1; j++)  {
      dp[i][j] = -1;
    }
  }
  for(int i=0; i<25; i++) {
    for(int j=0; j<25; j++) {
      E[i][j] = 0;
    }
  }
  for(int i=0, a, b; i<m; i++)  {
    cin >> a >> b;
    --a; --b;
    E[a][b] = 1;
    E[b][a] = 1;
  }
  long long ans = 0;
  for(int mask=0; mask<(1 << n); mask++)  {
    int first = first_bit(mask), cnt = __builtin_popcount(mask);
    for(int last = 0; last < n; last++) {
      if(E[last][first] and ((1 << last) & mask) and (cnt > 2))  {
        ans += f(mask, last);
      }
    }
  }

  cout << ans / 2 << "\n";
}


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

long long dp[(1 << 20) + 5][25];
int n, m, E[25][25];

int bit_count(int num)
{
  int ans = 0;
  for(int i=0; i<21; i++) {
    if(num & (1 << i))  {
      ans++;
    }
  }
  return ans;
}

int first_bit(int num)
{
  if(num == 0)
    return 21;
  for(int i=0; i<21; i++) {
    if(num & (1 << i))  {
      return i;
    }
  }
}

long long f(int mask, int last)
{
  int cnt = bit_count(mask), first = first_bit(mask), newmask = mask ^ (1 << last);
  if(cnt == 1)  {
    return (first == last) ? 1 : 0;
  }
  if(((mask & (1 << last)) == 0) || (first == last))  {
    return 0;
  }
  if(dp[mask][last] != -1) {
    return dp[mask][last];
  }

  long long ans = 0;
  for(int i = first; i<n; i++)  {
    if(E[last][i] and (mask & (1 << i)))  {
      ans += f(newmask, i);
    }
  }
  return dp[mask][last] = ans;
}

int main()
{
  ios::sync_with_stdio(false);
  cin >> n >> m;
  for(int i=0; i<(1 << n+1); i++) {
    for(int j=0; j<n+1; j++)  {
      dp[i][j] = -1;
    }
  }
  for(int i=0; i<25; i++) {
    for(int j=0; j<25; j++) {
      E[i][j] = 0;
    }
  }
  for(int i=0, a, b; i<m; i++)  {
    cin >> a >> b;
    --a; --b;
    E[a][b] = 1;
    E[b][a] = 1;
  }
  long long ans = 0;
  for(int mask=0; mask<(1 << n); mask++)  {
    int first = first_bit(mask), cnt = bit_count(mask);
    for(int last = 0; last < n; last++) {
      if(E[last][first] and ((1 << last) & mask) and (cnt > 2))  {
        ans += f(mask, last);
      }
    }
  }

  cout << ans / 2 << "\n";
}


#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <limits>
#include <set>
#include <cmath>
#include <cstring>

using namespace std;
#define pb push_back
#define MAXN 20
long long DP[1<<MAXN][MAXN];
long long N,M,A,B;
vector<int> adjlist[MAXN];
long long sol;
long long p;
long long calcola(int mask,int a)
{
    if(DP[mask][a]!=-1) return DP[mask][a];
    DP[mask][a]=0;
    for(auto i:adjlist[a])
    {
        if(i==p && (mask ^ (1<<a))!=M) DP[mask][a]++;
        else if(((1<<i)&mask) == 0) DP[mask][a]+=calcola((mask|(1<<i)),i);
    }
    return DP[mask][a];
}

int main()
{
	memset(DP,-1,sizeof DP);
	cin>>N>>M;
	for(int i=0;i<M;++i)
    {
        cin>>A>>B;
        adjlist[A].pb(B);
        adjlist[B].pb(A);
    }
    M=0;
    for(int i=1;i<=N;++i)
    {
        memset(DP,-1,sizeof DP);
        p=i;
        M|=(1<<i);
        sol+=calcola(M,i);
    }
    cout<<sol/2;
}


#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <limits>
#include <set>
#include <cmath>
#include <cstring>

using namespace std;
#define pb push_back
#define MAXN 21
long long DP[1<<MAXN][MAXN],conta[MAXN];
long long N,M,A,B;
vector<int> adjlist[MAXN];
long long sol;
long long p;
long long calcola(int mask,int a)
{
    if(DP[mask][a]!=-1) return DP[mask][a];
    DP[mask][a]=0;
    for(auto i:adjlist[a])
    {
        if(i==p && (mask ^ (1<<a))!=M) DP[mask][a]++;
        else if(((1<<i)&mask) == 0) DP[mask][a]+=calcola((mask|(1<<i)),i);
    }
    return DP[mask][a];
}

int main()
{
	memset(DP,-1,sizeof DP);
	cin>>N>>M;
	for(int i=0;i<M;++i)
    {
        cin>>A>>B;
        adjlist[A].pb(B);
        adjlist[B].pb(A);
    }
    M=0;
    for(int i=1;i<=N;++i)
    {
        memset(DP,-1,sizeof DP);
        memset(conta,0,sizeof conta);
        p=i;
        M|=(1<<i);
        sol+=calcola(M,i);
    }
    cout<<sol/2;
}


#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <time.h>
#include <vector>

#if LOCAL
	#define DO_NOT_SEND
#endif

typedef long long LL;

int IntMaxVal = (int) 1e20;
int IntMinVal = (int) -1e20;
LL LongMaxVal = (LL) 1e20;
LL LongMinVal = (LL) -1e20;

#define FOR(i, a, b) for(int i = a; i < b ; ++i)
#define FORD(i, a, b) for(int i = a; i >= b; --i)

#define minimize(a, b) { a = min(a, b); }
#define maximize(a, b) { a = max(a, b); }

#define all(v) v.begin(),v.end()

using namespace std;

#define next(type, i) type i; cin >> i;
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define nextVector(t, v, size) vector< argument_type<void(t)>::type > v(size); { for (int i = 0 ; i < size ; i++) cin >> v[i]; }

template <typename T1, typename T2>
istream& operator >>(istream& is, pair<T1, T2>& s)
{
    is >> s.first >> s.second;
    return is;
}

int main() {
	srand (time(NULL));
    ios_base::sync_with_stdio(false); cin.tie(NULL);

	next(int, n);
	next(int, m);

	nextVector((pair<int, int>), edges, m);
	for (auto &e : edges) {
		e.first--;
		e.second--;
	}
	bool hasEdge[n][n];
	FOR (i, 0, n) FOR (j, 0, n) hasEdge[i][j] = false;
	for (auto e : edges) hasEdge[e.first][e.second] = hasEdge[e.second][e.first] = true;

	LL res = 0;
	int maxMask = 1 << n;
	LL paths[n][maxMask];
	FORD (start, n - 1, 0) {
		int maxMask = 1 << start;
		FOR (i, 0, n) FOR (mask, 0, maxMask) paths[i][mask] = 0;

		FOR (mask, 1, maxMask) FOR (dest, 0, start) {
			if (mask & (1 << dest)) {
				if (mask == (1 << dest)) {
					if (hasEdge[start][dest]) {
						paths[dest][mask] = 1;
					}
				} else {
					FOR (mid, 0, start) if (mid != dest && (mask & (1 << mid)) && hasEdge[mid][dest]) {
						int prevMask = mask ^ (1 << dest);
						paths[dest][mask] += paths[mid][prevMask];
					}
					if (hasEdge[start][dest]) {
						res += paths[dest][mask];
					}
				}
			}
		}
	}

	cout << res / 2;
}


/*
    Tanvir Hasan Anick
    University of Asia pacific
*/
/**Header file**/
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
#include<list>
#include<iostream>
#include<assert.h>

/**Define file I/O **/
#define f_input freopen("input.txt","r",stdin)
#define f_output freopen("output.txt","w",stdout)

/**Define memory set function**/
#define mem(x,y) memset(x,y,sizeof(x))
#define CLEAR(x) memset(x,0,sizeof(x))

/**Define function and object**/
#define pb push_back
#define Sort(v) sort(v.begin(),v.end())
#define RSort(v) sort(v.rbegin(),v.rend())
#define CSort(v,C) sort(v.begin(),v.end(),C)
#define all(v) (v).begin(),(v).end()
#define sqr(x) ((x)*(x))
#define find_dist(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))

/**Define constant value**/
#define ERR 1e-9
#define pi (2*acos(0))
#define PI 3.141592653589793

/**Define input**/
#define scanint(a) scanf("%d",&a)
#define scanLLD(a) scanf("%lld",&a)
#define scanstr(s) scanf("%s",s)
#define scanline(l) scanf(" %[^\n]",l);

/**Define Bitwise operation**/
#define check(n, pos) (n & (1<<(pos)))
#define biton(n, pos) (n | (1<<(pos)))
#define bitoff(n, pos) (n & ~(1<<(pos)))

/**Define color**/
#define WHITE 0
#define GREY 1
#define BLACK 2

/**Sync off with stdio**/
#define __ cin.sync_with_stdio(false);\
           cin.tie();
/**Debug tools**/
#define what_is(x) cerr<<(#x)<<" is "<<x<<endl
using namespace std;

/**Typedef**/
typedef vector<int> vint;
typedef vector< vint > vint2D;
typedef vector<string> vstr;
typedef vector<char>vchar;
typedef vector< vchar >vchar2D;
typedef queue<int> Qi;
typedef queue< Qi > Qii;
typedef map<int,int> Mii;
typedef map<string,int> Msi;
typedef map<int,string> Mis;
typedef stack<int> stk;
typedef pair<int,int> pp;
typedef pair<int, pp > ppp;
typedef long long int LLD;
const int inf=0x7FFFFFFF;

/**Template & structure**/
struct point_int{int x,y;point_int(){}point_int(int a,int b){x=a,y=b;}}; ///Point for x,y (int) coordinate in 2D space
struct point_double{double x,y;point_double(){}point_double(double a,double b){x=a,y=b;}}; ///Point for x,y (double) coordinate in 2D space
struct Node{int v,w;Node() {}bool operator<(const Node &a)const{return w>a.w;}Node(int _v,int _w){v=_v,w=_w;}};///Node for Dijkstra
namespace my{
template<class T>T gcd(T a,T b){return b == 0 ? a : gcd(b, a % b);}
template<typename T>T lcm(T a, T b) {return a / gcd(a,b) * b;}
template<class T>T big_mod(T n,T p,T m){if(p==0)return (T)1;T x=big_mod(n,p/2,m);x=(x*x)%m;if(p&1)x=(x*n)%m;return x;}
template<class T>T multiplication(T n,T p,T m){if(p==0)return (T)0;T x=multiplication(n,p/2,m);x=(x+x)%m;if(p&1)x=(x+n)%m;return x;}
template<class T>T my_pow(T n,T p){if(p==0)return 1;T x=my_pow(n,p/2);x=(x*x);if(p&1)x=(x*n);return x;} ///n to the power p
template <class T> double getdist(T a, T b){return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}/// distance between a & b
template <class T> T extract(string s, T ret) {stringstream ss(s); ss >> ret; return ret;}/// extract words or numbers from a line
template <class T> string tostring(T n) {stringstream ss; ss << n; return ss.str();}/// convert a number to string
template<class T> inline T Mod(T n,T m) {return (n%m+m)%m;} ///For Positive Negative No.
template<class T> T MIN3(T a,T b,T c) {return min(a,min(b,c));} /// minimum of 3 number
template<class T> T MAX3(T a,T b,T c) {return max(a,max(b,c));} ///maximum of 3 number
template <class T> void print_vector(T &v){int sz=v.size();if(sz)cout<<v[0];for(int i = 1; i < sz; i++)cout << ' '<<v[i];cout<<endl;}/// prints all elements in a vector
bool isVowel(char ch){ ch=toupper(ch); if(ch=='A'||ch=='U'||ch=='I'||ch=='O'||ch=='E') return true; return false;}
bool isConsonant(char ch){if (isalpha(ch) && !isVowel(ch)) return true; return false;}}
/**Shortcut input function**/
int read_int(){int n;scanf("%d",&n);return n;}
int read_LLD(){LLD n;scanf("%lld",&n);return n;}
inline int buffer_input() { char inp[1000]; scanstr(inp); return atoi(inp); }

/**Direction**/
///int col[8] = {0, 1, 1, 1, 0, -1, -1, -1};int row[8] = {1, 1, 0, -1, -1, -1, 0, 1}; ///8 Direction
///int col[4] = {1, 0, -1, 0};int row[4] = {0, 1, 0, -1}; ///4 Direction
///int dx[]={2,1,-1,-2,-2,-1,1,2};int dy[]={1,2,2,1,-1,-2,-2,-1};///Knight Direction
///int dx[]={-1,-1,+0,+1,+1,+0};int dy[]={-1,+1,+2,+1,-1,-2}; ///Hexagonal Direction

/******************************Ajaira Jinish Sesh******************************/
vint graph[100];
LLD dp[1<<19][19];
LLD solve(int mask,int u,int st)
{
    LLD res=dp[mask][u];
    if(res!=-1)return res;
    res=0;
    for(int i=0;i<graph[u].size();i++)
    {
        int v=graph[u][i];
        if(v==st)
        {
            if(__builtin_popcount(mask)!=2)res++;
        }
        else if(v>st)
        {
            if((mask&(1<<v))==0)res+=solve(mask|(1<<v),v,st);
        }
    }
    return res;
}
int main()
{
    #ifdef _ANICK_
    //f_input;
    #endif // _ANICK_
    int N=buffer_input();
    int Edge=buffer_input();
    for(int i=0;i<Edge;i++)
    {
        int x=buffer_input()-1;
        int y=buffer_input()-1;
        graph[x].pb(y);
        graph[y].pb(x);
    }
    LLD ans=0;
    mem(dp,-1);
    for(int i=0;i<N;i++)
    {
        ans+=solve((1<<i),i,i)/2;
    }
    cout<<ans<<endl;
    return 0;
}


/*
    Tanvir Hasan Anick
    University of Asia pacific
*/
/**Header file**/
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
#include<list>
#include<iostream>
#include<assert.h>

/**Define file I/O **/
#define f_input freopen("input.txt","r",stdin)
#define f_output freopen("output.txt","w",stdout)

/**Define memory set function**/
#define mem(x,y) memset(x,y,sizeof(x))
#define CLEAR(x) memset(x,0,sizeof(x))

/**Define function and object**/
#define pb push_back
#define Sort(v) sort(v.begin(),v.end())
#define RSort(v) sort(v.rbegin(),v.rend())
#define CSort(v,C) sort(v.begin(),v.end(),C)
#define all(v) (v).begin(),(v).end()
#define sqr(x) ((x)*(x))
#define find_dist(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))

/**Define constant value**/
#define ERR 1e-9
#define pi (2*acos(0))
#define PI 3.141592653589793

/**Define input**/
#define scanint(a) scanf("%d",&a)
#define scanLLD(a) scanf("%lld",&a)
#define scanstr(s) scanf("%s",s)
#define scanline(l) scanf(" %[^\n]",l);

/**Define Bitwise operation**/
#define check(n, pos) (n & (1<<(pos)))
#define biton(n, pos) (n | (1<<(pos)))
#define bitoff(n, pos) (n & ~(1<<(pos)))

/**Define color**/
#define WHITE 0
#define GREY 1
#define BLACK 2

/**Sync off with stdio**/
#define __ cin.sync_with_stdio(false);\
           cin.tie();
/**Debug tools**/
#define what_is(x) cerr<<(#x)<<" is "<<x<<endl
using namespace std;

/**Typedef**/
typedef vector<int> vint;
typedef vector< vint > vint2D;
typedef vector<string> vstr;
typedef vector<char>vchar;
typedef vector< vchar >vchar2D;
typedef queue<int> Qi;
typedef queue< Qi > Qii;
typedef map<int,int> Mii;
typedef map<string,int> Msi;
typedef map<int,string> Mis;
typedef stack<int> stk;
typedef pair<int,int> pp;
typedef pair<int, pp > ppp;
typedef long long int LLD;
const int inf=0x7FFFFFFF;

/**Template & structure**/
struct point_int{int x,y;point_int(){}point_int(int a,int b){x=a,y=b;}}; ///Point for x,y (int) coordinate in 2D space
struct point_double{double x,y;point_double(){}point_double(double a,double b){x=a,y=b;}}; ///Point for x,y (double) coordinate in 2D space
struct Node{int v,w;Node() {}bool operator<(const Node &a)const{return w>a.w;}Node(int _v,int _w){v=_v,w=_w;}};///Node for Dijkstra
namespace my{
template<class T>T gcd(T a,T b){return b == 0 ? a : gcd(b, a % b);}
template<typename T>T lcm(T a, T b) {return a / gcd(a,b) * b;}
template<class T>T big_mod(T n,T p,T m){if(p==0)return (T)1;T x=big_mod(n,p/2,m);x=(x*x)%m;if(p&1)x=(x*n)%m;return x;}
template<class T>T multiplication(T n,T p,T m){if(p==0)return (T)0;T x=multiplication(n,p/2,m);x=(x+x)%m;if(p&1)x=(x+n)%m;return x;}
template<class T>T my_pow(T n,T p){if(p==0)return 1;T x=my_pow(n,p/2);x=(x*x);if(p&1)x=(x*n);return x;} ///n to the power p
template <class T> double getdist(T a, T b){return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}/// distance between a & b
template <class T> T extract(string s, T ret) {stringstream ss(s); ss >> ret; return ret;}/// extract words or numbers from a line
template <class T> string tostring(T n) {stringstream ss; ss << n; return ss.str();}/// convert a number to string
template<class T> inline T Mod(T n,T m) {return (n%m+m)%m;} ///For Positive Negative No.
template<class T> T MIN3(T a,T b,T c) {return min(a,min(b,c));} /// minimum of 3 number
template<class T> T MAX3(T a,T b,T c) {return max(a,max(b,c));} ///maximum of 3 number
template <class T> void print_vector(T &v){int sz=v.size();if(sz)cout<<v[0];for(int i = 1; i < sz; i++)cout << ' '<<v[i];cout<<endl;}/// prints all elements in a vector
bool isVowel(char ch){ ch=toupper(ch); if(ch=='A'||ch=='U'||ch=='I'||ch=='O'||ch=='E') return true; return false;}
bool isConsonant(char ch){if (isalpha(ch) && !isVowel(ch)) return true; return false;}}
/**Shortcut input function**/
int read_int(){int n;scanf("%d",&n);return n;}
int read_LLD(){LLD n;scanf("%lld",&n);return n;}
inline int buffer_input() { char inp[1000]; scanstr(inp); return atoi(inp); }

/**Direction**/
///int col[8] = {0, 1, 1, 1, 0, -1, -1, -1};int row[8] = {1, 1, 0, -1, -1, -1, 0, 1}; ///8 Direction
///int col[4] = {1, 0, -1, 0};int row[4] = {0, 1, 0, -1}; ///4 Direction
///int dx[]={2,1,-1,-2,-2,-1,1,2};int dy[]={1,2,2,1,-1,-2,-2,-1};///Knight Direction
///int dx[]={-1,-1,+0,+1,+1,+0};int dy[]={-1,+1,+2,+1,-1,-2}; ///Hexagonal Direction

/******************************Ajaira Jinish Sesh******************************/
vint graph[100];
LLD dp[1<<19][19];
LLD solve(int mask,int u,int st)
{
    LLD &res=dp[mask][u];
    if(res!=-1)return res;
    res=0;
    for(auto v:graph[u])
    {
        if(v==st)
        {
            if(__builtin_popcount(mask)!=2)res++;
        }
        else if(v>st)
        {
            if((mask&(1<<v))==0)res+=solve(mask|(1<<v),v,st);
        }
    }
    return res;
}
int main()
{
    #ifdef _ANICK_
    //f_input;
    #endif // _ANICK_
    int N=buffer_input();
    int Edge=buffer_input();
    for(int i=0;i<Edge;i++)
    {
        int x=buffer_input()-1;
        int y=buffer_input()-1;
        graph[x].pb(y);
        graph[y].pb(x);
    }
    LLD ans=0;
    mem(dp,-1);
    for(int i=0;i<N;i++)
    {
        ans+=solve((1<<i),i,i)/2;
    }
    cout<<ans<<endl;
    return 0;
}


/*
    Tanvir Hasan Anick
    University of Asia pacific
*/
/**Header file**/
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
#include<list>
#include<iostream>
#include<assert.h>

/**Define file I/O **/
#define f_input freopen("input.txt","r",stdin)
#define f_output freopen("output.txt","w",stdout)

/**Define memory set function**/
#define mem(x,y) memset(x,y,sizeof(x))
#define CLEAR(x) memset(x,0,sizeof(x))

/**Define function and object**/
#define pb push_back
#define Sort(v) sort(v.begin(),v.end())
#define RSort(v) sort(v.rbegin(),v.rend())
#define CSort(v,C) sort(v.begin(),v.end(),C)
#define all(v) (v).begin(),(v).end()
#define sqr(x) ((x)*(x))
#define find_dist(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))

/**Define constant value**/
#define ERR 1e-9
#define pi (2*acos(0))
#define PI 3.141592653589793

/**Define input**/
#define scanint(a) scanf("%d",&a)
#define scanLLD(a) scanf("%lld",&a)
#define scanstr(s) scanf("%s",s)
#define scanline(l) scanf(" %[^\n]",l);

/**Define Bitwise operation**/
#define check(n, pos) (n & (1<<(pos)))
#define biton(n, pos) (n | (1<<(pos)))
#define bitoff(n, pos) (n & ~(1<<(pos)))

/**Define color**/
#define WHITE 0
#define GREY 1
#define BLACK 2

/**Sync off with stdio**/
#define __ cin.sync_with_stdio(false);\
           cin.tie();
/**Debug tools**/
#define what_is(x) cerr<<(#x)<<" is "<<x<<endl
using namespace std;

/**Typedef**/
typedef vector<int> vint;
typedef vector< vint > vint2D;
typedef vector<string> vstr;
typedef vector<char>vchar;
typedef vector< vchar >vchar2D;
typedef queue<int> Qi;
typedef queue< Qi > Qii;
typedef map<int,int> Mii;
typedef map<string,int> Msi;
typedef map<int,string> Mis;
typedef stack<int> stk;
typedef pair<int,int> pp;
typedef pair<int, pp > ppp;
typedef long long int LLD;
const int inf=0x7FFFFFFF;

/**Template & structure**/
struct point_int{int x,y;point_int(){}point_int(int a,int b){x=a,y=b;}}; ///Point for x,y (int) coordinate in 2D space
struct point_double{double x,y;point_double(){}point_double(double a,double b){x=a,y=b;}}; ///Point for x,y (double) coordinate in 2D space
struct Node{int v,w;Node() {}bool operator<(const Node &a)const{return w>a.w;}Node(int _v,int _w){v=_v,w=_w;}};///Node for Dijkstra
namespace my{
template<class T>T gcd(T a,T b){return b == 0 ? a : gcd(b, a % b);}
template<typename T>T lcm(T a, T b) {return a / gcd(a,b) * b;}
template<class T>T big_mod(T n,T p,T m){if(p==0)return (T)1;T x=big_mod(n,p/2,m);x=(x*x)%m;if(p&1)x=(x*n)%m;return x;}
template<class T>T multiplication(T n,T p,T m){if(p==0)return (T)0;T x=multiplication(n,p/2,m);x=(x+x)%m;if(p&1)x=(x+n)%m;return x;}
template<class T>T my_pow(T n,T p){if(p==0)return 1;T x=my_pow(n,p/2);x=(x*x);if(p&1)x=(x*n);return x;} ///n to the power p
template <class T> double getdist(T a, T b){return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}/// distance between a & b
template <class T> T extract(string s, T ret) {stringstream ss(s); ss >> ret; return ret;}/// extract words or numbers from a line
template <class T> string tostring(T n) {stringstream ss; ss << n; return ss.str();}/// convert a number to string
template<class T> inline T Mod(T n,T m) {return (n%m+m)%m;} ///For Positive Negative No.
template<class T> T MIN3(T a,T b,T c) {return min(a,min(b,c));} /// minimum of 3 number
template<class T> T MAX3(T a,T b,T c) {return max(a,max(b,c));} ///maximum of 3 number
template <class T> void print_vector(T &v){int sz=v.size();if(sz)cout<<v[0];for(int i = 1; i < sz; i++)cout << ' '<<v[i];cout<<endl;}/// prints all elements in a vector
bool isVowel(char ch){ ch=toupper(ch); if(ch=='A'||ch=='U'||ch=='I'||ch=='O'||ch=='E') return true; return false;}
bool isConsonant(char ch){if (isalpha(ch) && !isVowel(ch)) return true; return false;}}
/**Shortcut input function**/
int read_int(){int n;scanf("%d",&n);return n;}
int read_LLD(){LLD n;scanf("%lld",&n);return n;}
inline int buffer_input() { char inp[1000]; scanstr(inp); return atoi(inp); }

/**Direction**/
///int col[8] = {0, 1, 1, 1, 0, -1, -1, -1};int row[8] = {1, 1, 0, -1, -1, -1, 0, 1}; ///8 Direction
///int col[4] = {1, 0, -1, 0};int row[4] = {0, 1, 0, -1}; ///4 Direction
///int dx[]={2,1,-1,-2,-2,-1,1,2};int dy[]={1,2,2,1,-1,-2,-2,-1};///Knight Direction
///int dx[]={-1,-1,+0,+1,+1,+0};int dy[]={-1,+1,+2,+1,-1,-2}; ///Hexagonal Direction

/******************************Ajaira Jinish Sesh******************************/
vint graph[100];
LLD dp[1<<19][19];
LLD solve(int mask,int u,int st)
{
    LLD res=dp[mask][u];
    if(res!=-1)return res;
    res=0;
    for(auto v:graph[u])
    {
        if(v==st)
        {
            if(__builtin_popcount(mask)!=2)res++;
        }
        else if(v>st)
        {
            if((mask&(1<<v))==0)res+=solve(mask|(1<<v),v,st);
        }
    }
    return res;
}
int main()
{
    #ifdef _ANICK_
    //f_input;
    #endif // _ANICK_
    int N=buffer_input();
    int Edge=buffer_input();
    for(int i=0;i<Edge;i++)
    {
        int x=buffer_input()-1;
        int y=buffer_input()-1;
        graph[x].pb(y);
        graph[y].pb(x);
    }
    LLD ans=0;
    mem(dp,-1);
    for(int i=0;i<N;i++)
    {
        ans+=solve((1<<i),i,i)/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include <iostream>
#include <vector>

using namespace std;

typedef long long ll;

vector<int> g[20];

ll dp[1<<20][20];

int main(){
    int n,m;
    cin>>n>>m;
    for (int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        a--;
        b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i=0;i<n;i++){
        dp[1<<i][i]=1;
    }
    ll v=0;
    for (int i=0;i<(1<<n);i++){
        int f=0;
        int ff=0;
        for (int ii=0;ii<n;ii++){
            if ((1<<ii)&i){
                ff++;
                if (ff==1){
                    f=ii;
                    continue;
                }
                for (int nx:g[ii]){
                    dp[i][ii]+=dp[i-(1<<ii)][nx];
                }
            }
        }
        if (ff>=3){
            for (int ii=0;ii<n;ii++){
                int fff=0;
                for (int nx:g[ii]){
                    if (nx==f) {
                        fff=1;
                        break;
                    }
                }
                if (fff){
                    v+=dp[i][ii];
                }
            }
        }
    }
    cout<<v/2<<endl;
}


#include <bits/stdc++.h>

using namespace std;

int d[(1 << 19)][19];
bool u[(1 << 19)];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

inline int Bits (int i)
{
     i = i - ((i >> 1) & 0x55555555);
     i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
     return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[1 << j][j] = 1;
		for (int i = 0; i < (1 << n); ++i) {
			if (bit (i, j)) {
				for (int k = 0; k < n; ++k) {
					if (!d[i][k] || !bit (i, k))
						continue;
					for (int it : g[k]) {
						if (bit (i, it))
							continue;
						d[i | (1 << it)][it] += d[i][k];
					}
				}
			}
		}
		for (int i = 0; i < (1 << n); ++i) {
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[i][k];

				for (int k = 0; k < n; ++k)
					if (bit (i, k)) {
						ans += calc / 2 * (k == j);
						break;
					}
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll d[19][(1 << 19)];
bool u[(1 << 19)];
ll n, m, x, y;
ll ans;
vector <ll> g[19];

inline bool bit (const ll &mask, const ll &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (ll i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (ll j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (ll i = (1 << j); i < (1 << n) && i < (1 << (j + 1)); i = (i + 1) | (1 << j)) {
			for (ll k = 0; k < n; ++k) {
				if (!d[k][i] || !bit (i, k))
					continue;
				for (ll it : g[k]) {
					if (bit (i, it))
						continue;
					d[it][i | (1 << it)] += d[k][i];
				}
			}
		}
		for (ll i = 0; i < (1 << (j + 1)); ++i) {
			if (bit (i, j)) {
				ll calc = 0;
				for (ll k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];
				ans += (calc / 2);
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int d[(1 << 19)][19];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, int && pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[1 << j][j] = 1;
		for (int i = 0; i < (1 << n); ++i) {
			for (int k = 0; k < n; ++k) {
				if (!d[i][k])
					continue;
				if (j == k)
					ans += (d[i][k] >> 1);
				for (int it : g[k]) {
					if (bit (i, 1 << it))
						continue;
					d[i | (1 << it)][it] += d[i][k];
				}
			}
		}
	}
	cout << ans;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll d[19][(1 << 19)];
bool u[(1 << 19)];
ll n, m, x, y;
ll ans;
vector <ll> g[19];

inline bool bit (const ll &mask, const ll &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (ll i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (ll j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (ll i = (1 << j); i < (1 << n) && i < (1 << (j + 1)); i = (i + 1) | (1 << j)) {
			for (ll k = 0; k < n; ++k) {
				if (!d[k][i] || !bit (i, k))
					continue;
				for (ll it : g[k]) {
					if (bit (i, it))
						continue;
					d[it][i | (1 << it)] += d[k][i];
				}
			}
			if (i == (1 << (j + 1)) - 1)
				break;
		}
		for (ll i = 0; i < (1 << (j + 1)); ++i) {
			if (bit (i, j)) {
				ll calc = 0;
				for (ll k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];
				ans += (calc / 2);
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}
/*
inline int Bits (int i)
{
     i = i - ((i >> 1) & 0x55555555);
     i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
     return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
*/
int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}
	int i, j, k;
	for (j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (i = 0; i < (1 << n); ++i)
			if (bit (i, j))
				for (k = 0; k < n; ++k) {
					if (!d[k][i] || !bit (i, k))
						continue;
					for (int it : g[k]) {
						if (bit (i, it))
							continue;
						d[it][i | (1 << it)] += d[k][i];
					}
				}
		for (i = 0; i < (1 << n); ++i)
			if (bit (i, j)) {
				int calc = 0;
				for (int it : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];

				for (k = 0; k < n; ++k)
					if (bit (i, k)) {
						ans += calc / 2 * (k == j);
						break;
					}
			}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (int i = (1 << j); i < (1 << n); i = (i + 1) | (1 << j))
			if (bit (i, j))
				for (int k = 0; k < n; ++k) {
					if (!d[k][i] || !bit (i, k))
						continue;
					for (int it : g[k]) {
						if (bit (i, it))
							continue;
						d[it][i | (1 << it)] += d[k][i];
					}
				}
		for (int i = 0; i < (1 << n); ++i)
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];

				for (int k = 0; k < n; ++k)
					if (bit (i, k)) {
						ans += calc / 2 * (k == j);
						break;
					}
			}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (int i = (1 << j); i < (1 << n) && i < (1 << (j + 1)); i = (i + 1) | (1 << j)) {
			for (int k = 0; k < n; ++k) {
				if (!d[k][i] || !bit (i, k))
					continue;
				for (int it : g[k]) {
					if (bit (i, it))
						continue;
					d[it][i | (1 << it)] += d[k][i];
				}
			}
			if (i == (1 << (j + 1)) - 1)
				break;
		}
		for (int i = 0; i < (1 << (j + 1)); ++i) {
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];
				ans += (calc / 2);
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y;
ll ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (int i = (1 << j); i < (1 << n) && i < (1 << (j + 1)); i = (i + 1) | (1 << j)) {
			for (int k = 0; k < n; ++k) {
				if (!d[k][i] || !bit (i, k))
					continue;
				for (int it : g[k]) {
					if (bit (i, it))
						continue;
					d[it][i | (1 << it)] += d[k][i];
				}
			}
			if (i == (1 << (j + 1)) - 1)
				break;
		}
		for (int i = 0; i < (1 << (j + 1)); ++i) {
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];
				ans += (calc / 2);
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y;
ll ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (int i = (1 << j); i < (1 << n) && i < (1 << (j + 1)); i = (i + 1) | (1 << j)) {
			for (int k = 0; k < n; ++k) {
				if (!d[k][i] || !bit (i, k))
					continue;
				for (int it : g[k]) {
					if (bit (i, it))
						continue;
					d[it][i | (1 << it)] += d[k][i];
				}
			}
			if (i == (1 << (j + 1)) - 1)
				break;
		}
		for (int i = 0; i < (1 << (j + 1)); ++i) {
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];
				ans += (calc / 2);
			}
		}
	}

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int d[19][(1 << 19)];
bool u[(1 << 19)];
int n, m, x, y, ans;
vector <int> g[19];

inline bool bit (const int &mask, const int &pos) {
	return (mask >> pos) & 1;
}

inline int Bits (int i)
{
     i = i - ((i >> 1) & 0x55555555);
     i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
     return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

int main () {
	#ifndef ONLINE_JUDGE
	freopen ("in", "r", stdin);
	freopen ("out", "w", stdout);
	#endif
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		cin >> x >> y;
		--x, --y;
		g[x].push_back (y);
		g[y].push_back (x);
	}

	for (int j = 0; j < n; ++j) {
		memset (d, 0, sizeof (d));
		d[j][1 << j] = 1;
		for (int i = 0; i < (1 << n); ++i)
			if (bit (i, j))
				for (int k = 0; k < n; ++k) {
					if (!d[k][i] || !bit (i, k))
						continue;
					for (int it : g[k]) {
						if (bit (i, it))
							continue;
						d[it][i | (1 << it)] += d[k][i];
					}
				}
		for (int i = 0; i < (1 << n); ++i)
			if (bit (i, j)) {
				int calc = 0;
				for (int k : g[j])
					if (bit (i, j) && k != j)
						calc += d[k][i];

				for (int k = 0; k < n; ++k)
					if (bit (i, k)) {
						ans += calc / 2 * (k == j);
						break;
					}
			}
	}

	cout << ans;

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))

long long m[1<<21][21],n;
vector<vector<int> > adj(100);

long long f(int nodes,int st,int cur)
{
    long long &ret = m[nodes][cur];

    if(ret != -1)return ret;

 //   if(!(cur>st||((st==cur)&&!get(nodes,st))))while(true);

    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{
    int a,b,ind = 0;
    map<int,int> mp;
    while(cin>>a>>b)
    {
        if(mp.find(a)==mp.end())mp[a] = ind++;
        if(mp.find(b)==mp.end())mp[b] = ind++;

        a = mp[a];
        b = mp[b];

        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    n = mp.size();
    //cout<<n<<endl;
    long long ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);

        ans+=t/2LL;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))
int m[1<<19][19],n;
vector<vector<int> > adj(20);
void show(int x){
for(int i=0;i<19;++i)
    if(get(x,i))cout<<i+1<<" ";
cout<<endl;
}
int f(int nodes,int st,int cur)
{

    int &ret = m[nodes][cur];

    if(ret != -1)return ret;
    assert(cur>st||((st==cur)&&!get(nodes,st)));
    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{

    int a,b;
    while(cin>>a>>b)
    {
        n = max(max(a,b),n);
        a--;b--;
        adj[a].push_back(b);
        adj[b].push_back(a);

    }
    int ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);
       // cout<<"st  "<<i<<" "<<t<<endl;
        ans+=t/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))
int m[1<<19][19],n;
vector<vector<int> > adj(20);
void show(int x){
for(int i=0;i<19;++i)
    if(get(x,i))cout<<i+1<<" ";
cout<<endl;
}
int f(int nodes,int st,int cur)
{

    int &ret = m[nodes][cur];

    if(ret != -1)return ret;

    if(!(cur>st||((st==cur)&&!get(nodes,st))))while(true);

    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{
    int a,b,ind = 0;
    map<int,int> mp;
    while(cin>>a>>b)
    {
        if(mp.find(a)==mp.end())mp[a] = ind++;
        if(mp.find(b)==mp.end())mp[b] = ind++;

        a = mp[a];
        b = mp[b];
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    n = mp.size();
    int ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);
       // cout<<"st  "<<i<<" "<<t<<endl;
        ans+=t/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))
int m[1<<19][19],n;
vector<vector<int> > adj(20);
void show(int x){
for(int i=0;i<19;++i)
    if(get(x,i))cout<<i+1<<" ";
cout<<endl;
}
int f(int nodes,int st,int cur)
{

    int &ret = m[nodes][cur];

    if(ret != -1)return ret;
    if(!(cur>st||((st==cur)&&!get(nodes,st))))while(true);
    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{

    int a,b;
    while(cin>>a>>b)
    {
        n = max(max(a,b),n);
        a--;b--;
        adj[a].push_back(b);
        adj[b].push_back(a);

    }
    int ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);
       // cout<<"st  "<<i<<" "<<t<<endl;
        ans+=t/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))
int m[1<<19][19][19],n;
vector<vector<int> > adj(20);
void show(int x){
for(int i=0;i<19;++i)
    if(get(x,i))cout<<i+1<<" ";
cout<<endl;
}
int f(int nodes,int st,int cur)
{

    //int &ret = m[nodes][st][cur];
    int ret = -1;
    if(ret != -1)return ret;
    assert(cur>st||((st==cur)&&!get(nodes,st)));
    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{

    memset(m,-1,sizeof m);
    int a,b;
    while(cin>>a>>b)
    {
        n = max(max(a,b),n);
        a--;b--;
        adj[a].push_back(b);
        adj[b].push_back(a);

    }
    int ans = 0,t;
    for(int i=0;i<n;++i)
    {
        t = f(0,i,i);
       // cout<<"st  "<<i<<" "<<t<<endl;
        ans+=t/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))
int m[1<<21][21],n;
vector<vector<int> > adj(100);
void show(int x){
for(int i=0;i<19;++i)
    if(get(x,i))cout<<i+1<<" ";
cout<<endl;
}
int f(int nodes,int st,int cur)
{
    int &ret = m[nodes][cur];

    if(ret != -1)return ret;

 //   if(!(cur>st||((st==cur)&&!get(nodes,st))))while(true);

    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{
    int a,b,ind = 0;
    map<int,int> mp;
    while(cin>>a>>b)
    {
        if(mp.find(a)==mp.end())mp[a] = ind++;
        if(mp.find(b)==mp.end())mp[b] = ind++;

        a = mp[a];
        b = mp[b];

        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    n = mp.size();
    //cout<<n<<endl;
    int ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);
       // cout<<"st  "<<i<<" "<<t<<endl;
        ans+=t/2;
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define get(m,i) (((m)>>(i))&1)

#define on(m,i) ((1<<(i))|(m))
#define off(m,i) ((~(1<<(i)))&(m))

long long m[1<<20][20],n;
vector<vector<int> > adj(100);

long long f(int nodes,int st,int cur)
{
    long long &ret = m[nodes][cur];

    if(ret != -1)return ret;

 //   if(!(cur>st||((st==cur)&&!get(nodes,st))))while(true);

    ret = 0;
    nodes = on(nodes,cur);
    for(int i = 0;i<adj[cur].size();++i)
    {
        int p = adj[cur][i];
        if(get(nodes,p))
        {
            if(p==st&&nodes!=((1<<st)|(1<<cur))){ret++;/*show(nodes);*/}
        }else if(p>st)ret+= f(nodes,st,p);
    }

    return ret;
}
int main()
{
    int a,b,ind = 0;
    map<int,int> mp;
    while(cin>>a>>b)
    {
        if(mp.find(a)==mp.end())mp[a] = ind++;
        if(mp.find(b)==mp.end())mp[b] = ind++;

        a = mp[a];
        b = mp[b];

        adj[a].push_back(b);
        adj[b].push_back(a);
    }

    n = mp.size();
    //cout<<n<<endl;
    long long ans = 0,t;
    for(int i=0;i<n;++i)
    {
        memset(m,-1,sizeof m);
        t = f(0,i,i);

        ans+=t/2LL;
    }
    cout<<ans<<endl;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}

	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j&&g[j][k]==1){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];}

			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
			if(i==(1<<15))cout<<sum/2;

		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
int g[20][20];
int dp[1048575][20];

int bit(int mask, int index)
	{
		index++;
		int temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int mask){
		int stop = mask*2;
		int temp = 1;
		int cnt = 0;
		while(temp<stop){
		if((mask&temp)==temp)cnt++;
		temp = (temp<<1);
		}
		return cnt;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	int n,m;
	cin>>n>>m;
	for(int i =0; i < 20; i++){
			for(int j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	int x,y;
	for(int i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
	}
	int k = bit(32,4);

	int stop = (1<<n);
	stop--;
	for(int i = 0; i <= stop; i++){
		for(int j =0; j<n;j++){
			if(count(i)==1&&bit(i,j)==1){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(int i = 0; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					int ind = (i^(1<<j));
					dp[i][j] += dp[ind][k];
				}
			}
		}
	}
	int sum = 0;
		for(int i = 0; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
		}

    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					int ind = (i^(1<<j));
					if(g[k][j]==1){
						dp[i][j] += dp[ind][k];}
				}
			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}

		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
long long count(long long mask){
		long long stop = mask*2;
		long long temp = 1;
		long long cnt = 0;
		while(temp<stop){
		if((mask&temp)==temp)cnt++;
		temp = (temp<<1);
		}
		return cnt;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 0; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if(count(i)==1&&bit(i,j)==1){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(long long i = 0; i <= stop; i++){
		for(long long j =0; j<n;j++){
			for(long long k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					long long ind = (i^(1<<j));
					dp[i][j] += dp[ind][k];
				}
			}
		}
	}
	long long sum = 0;
		for(long long i = 0; i <= stop; i++){
			for(long long j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
		}
		cout<<sum;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int first(int m){
	int cou = 0;
	while(m>0){cou++;
	if((m&1)==1)break;
	m= (m>>1);
	}
	cou--;
	return cou;
}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <m; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 0; i < n; i++){
			dp[(1<<i)][i] = 1;
	}
	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			if(bit(i,j)==1&&j>first(i)){
			for(int k = 0; k < n; k++){
				if(i==11){
				int q = 10;
				}
				if(bit(i,k)==1&&g[j][k]==1&&count(i)>1){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];
				}
			}
			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){

				int tt = first(i);
				if(count(i)>=3){
					sum+=dp[i][j];
					if(sum<0||dp[i][j]<0)cout<<sum/2<<endl;
				}
			}
		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
int g[20][20];
int dp[1048575][20];

int bit(int mask, int index)
	{
		index++;
		int temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int mask){
		int stop = mask*2;
		int temp = 1;
		int cnt = 0;
		while(temp<stop){
		if((mask&temp)==temp)cnt++;
		temp = (temp<<1);
		}
		return cnt;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	int n,m;
	cin>>n>>m;
	for(int i =0; i < 20; i++){
			for(int j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	int x,y;
	for(int i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
	}
	int k = bit(32,4);

	int stop = (1<<n);
	stop--;
	for(int i = 0; i <= stop; i++){
		for(int j =0; j<n;j++){
			if(count(i)==1&&bit(i,j)==1){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(int i = 0; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					int ind = (i^(1<<j));
					dp[i][j] += dp[ind][k];
				}
			}
		}
	}
	int sum = 0;
		for(int i = 0; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
		}
		cout<<sum;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int first(int m){
	int cou = 0;
	while(m>0){cou++;
	if((m&1)==1)break;
	m= (m>>1);
	}
	cou--;
	return cou;
}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <m; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 0; i < n; i++){
			dp[(1<<i)][i] = 1;
	}
	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			if(bit(i,j)==1&&j>first(i)){
			for(int k = 0; k < n; k++){
				if(i==11){
				int q = 10;
				}
				if(bit(i,k)==1&&g[j][k]==1&&count(i)>1){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];
				}
			}
			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){

				int tt = first(i);
				if(count(i)>=3&&g[first(i)][j]==1){
					sum+=dp[i][j];
					if(sum<0||dp[i][j]<0)cout<<sum/2<<endl;
				}
			}
		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int first(int m){
	int cou = 0;
	while(m>0){
	if((m&1)==1)break;
	m= (m>>1);cou++;
	}
	return cou;
}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 0; i < n; i++){
			dp[(1<<i)][i] = 1;
	}

	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			if(bit(i,j)==1&&j!=first(i)){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&g[j][k]==1&&count(i)>1){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];
				}
			}
			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
					if(sum<0||dp[i][j]<0)cout<<sum/2<<endl;
				}
			}
		}

		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
long long count(long long mask){
		long long stop = mask*2;
		long long temp = 1;
		long long cnt = 0;
		while(temp<stop){
		if((mask&temp)==temp)cnt++;
		temp = (temp<<1);
		}
		return cnt;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			for(long long k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					long long ind = (i^(1<<j));
					if(g[k][j]==1){
						dp[i][j] += dp[ind][k];}
				}
			}
		}
	}
	long long sum = 0;
		for(long long i = 1; i <= stop; i++){
			for(long long j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];}

			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}

		}
		cout<<sum/(2*n)+1;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}

	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j&&g[j][k]==1){
					int ind = (i^(1<<j));
						dp[i][j] += dp[ind][k];}

			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}

		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
int count(int n)
{
   int i = 0;
    for (;n;++i) n&=n-1;
    return i;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(int i = 1; i <= stop; i++){
		for(int j =0; j<n;j++){
			for(int k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					int ind = (i^(1<<j));
					if(g[k][j]==1){
						dp[i][j] += dp[ind][k];}
				}
			}
		}
	}
	long long sum = 0;
		for(int i = 1; i <= stop; i++){
			for(int j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}

		}
		cout<<sum/2;
    return 0;
}


// �����.cpp: ������� ���� �������.
//#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
long long g[20][20];
long long dp[1048575][20];

long long bit(long long mask, long long index)
	{
		//index++;
		long long temp = (1<<index);
		return ((mask&temp)==temp)?(1):(0);
	}
long long count(long long mask){
		long long stop = mask*2;
		long long temp = 1;
		long long cnt = 0;
		while(temp<stop){
		if((mask&temp)==temp)cnt++;
		temp = (temp<<1);
		}
		return cnt;
}

int main() {
	//freopen("input.txt", "r",stdin);
	//freopen("output.txt", "w", stdout);
	long long n,m;
	cin>>n>>m;
	for(long long i =0; i < 20; i++){
			for(long long j =0; j < 20; j++){
				g[i][j] = 0;
			}
	}
	long long x,y;
	for(long long i = 0; i <n; i++){
		cin>>x>>y;
		x--;y--;
		g[x][y] = 1;
		g[y][x] = 1;
	}
	long long k = bit(32,4);

	long long stop = (1<<n);
	stop--;
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			if((count(i)==1)&&(bit(i,j)==1)){
				dp[i][j] = 1;
			}else{
				dp[i][j] = 0;
			}
		}
	}
	for(long long i = 1; i <= stop; i++){
		for(long long j =0; j<n;j++){
			for(long long k = 0; k < n; k++){
				if(bit(i,k)==1&&k!=j){
					long long ind = (i^(1<<j));
					if(g[k][j]==1){
						dp[i][j] += dp[ind][k];}
				}
			}
		}
	}
	long long sum = 0;
		for(long long i = 1; i <= stop; i++){
			for(long long j =0; j<n;j++){
				if(count(i)>=3){
					sum+=dp[i][j];
				}
			}
			sum=sum/2;
		}
		cout<<sum;
    return 0;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
/*#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>*/

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
	if (!mark) return;
	freopen(in_file.c_str(), "r", stdin);
	//freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
	file_io("input.in", "input.in", 0);
	cin.tie(null);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	int ML = (1 << (n + 1));
	/*for (int i = 0; i < 20; ++i)
		for (int j = 0; j < 20; ++j)
			g[i][j] = 0;
	for (int i = 0; i < ML; ++i)
		for (int j = 0; j < 20; ++j)
			dp[i][j] = 0;*/
	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		g[u][v] = g[v][u] = 1;
	}
	i64 ans = 0;
	for (int mask = 1; mask < ML; ++mask) {
		int fone = 0;
		while (!(mask & (1 << fone)))
			++fone;
		for (int end = 1; end <= n; ++end)
			if (mask & (1 << end)) {
				if (mask == (1 << end))
					dp[mask][end] = 1;
				if(!dp[mask][end]) continue;
				if (mask != (1 << fone) + (1 << end))
					ans += dp[mask][end] * g[end][fone];
				for (int to = fone + 1; to <= n; ++to)
					if (!(mask & (1 << to)))
						dp[mask + (1 << to)][to] += dp[mask][end] * g[end][to];
			}
	}
	cout << ans / 2 << endl;
	return exit_scs;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
/*#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>*/

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
	if (!mark) return;
	freopen(in_file.c_str(), "r", stdin);
	//freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
	file_io("input.in", "input.in", 0);
	cin.tie(null);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	int ML = (1 << n);
	/*for (int i = 0; i < 20; ++i)
		for (int j = 0; j < 20; ++j)
			g[i][j] = 0;
	for (int i = 0; i < ML; ++i)
		for (int j = 0; j < 20; ++j)
			dp[i][j] = 0;*/
	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		--u, --v;
		g[u][v] = g[v][u] = 1;
	}
	i64 ans = 0;
	for (int mask = 0; mask < ML; ++mask) {
		int fone = 0;
		for(int i=0; i < n; ++i)
			if(mask & (1<<i)) {
				fone = i;
				break;
			}
		for (int end = 0; end < n; ++end)
			if (mask & (1 << end)) {
				if (mask == (1 << end))
					dp[mask][end] = 1;
				if(!dp[mask][end]) continue;
				if (mask != (1 << fone) + (1 << end))
					ans += dp[mask][end] * g[end][fone];
				for (int to = fone + 1; to < n; ++to)
					if (!(mask & (1 << to)))
						dp[mask + (1 << to)][to] += dp[mask][end] * g[end][to];
			}
	}
	cout << ans / 2 << endl;
	return exit_scs;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
/*#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>*/

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
	if (!mark) return;
	freopen(in_file.c_str(), "r", stdin);
	//freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
	//file_io("input.in", "output.out", 1);
	cin.tie(null);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	int ML = (1 << n);
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= n; ++j)
			g[i][j] = 0;
	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		g[u][v] = g[v][u] = 1;
	}
	for(int mask = 0; mask < ML; ++mask)
		for(int end = 0; end <= n; ++end)
			dp[mask][end] = 0;
	i64 ans = 0;
	for (int mask = 1; mask < ML; ++mask) {
		int fone = 0;
		while (!(mask & (1 << fone)))
			++fone;
		for (int end = 1; end <= n; ++end) {
			if(end == fone)
				dp[mask][end] = 1;
			if (mask & (1 << end))
				for (int to = 1; to <= n; ++to)
					if (!(mask & (1 << to)))
						dp[mask + (1 << to)][to] += g[end][to] * dp[mask][end];
		}
		for(int end = 1; end <= n; ++end) {
			if((mask & (1 << end)) && g[end][fone])
				ans += dp[mask][end];
		}
	}
	cout << ans << endl;
	return exit_scs;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
/*#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>*/

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
    if (!mark) return;
    freopen(in_file.c_str(), "r", stdin);
    //freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
    file_io("input.in", "input.in", 0);
    cin.tie(null);
    ios_base::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    int ML = (1 << n);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        g[u][v] = g[v][u] = 1;
    }
    i64 ans = 0;
    for (int mask = 0; mask < ML; ++mask) {
        int fone = __builtin_ffs(mask) - 1;
        for (int end = 0; end < n; ++end)
            if (mask & (1 << end)) {
                if (mask == (1 << end))
                    dp[mask][end] = 1;
                if(!dp[mask][end]) continue;
                if (mask != (1 << fone) + (1 << end))
                    ans += dp[mask][end] * g[end][fone];
                for (int to = fone + 1; to < n; ++to)
                    if (!(mask & (1 << to)))
                        dp[mask + (1 << to)][to] += dp[mask][end] * g[end][to];
            }
    }
    cout << ans / 2 << endl;
    return exit_scs;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <unordered_map>
#include <unordered_set>

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
	if (!mark) return;
	freopen(in_file.c_str(), "r", stdin);
	freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
	file_io("input.in", "output.out", 0);
	cin.tie(null);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	int ML = (1 << n);
	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		--u, --v;
		g[u][v] = g[v][u] = 1;
	}
	i64 ans = 0;
	for (int mask = 0; mask < ML; ++mask) {
		int fone = 0;
		for (int i = 0; i < n; ++i)
			if (mask & (1 << i)) {
				fone = i;
				break;
			}
		for (int end = 0; end < n; ++end)
			if (mask & (1 << end)) {
				if (mask == (1 << end))
					dp[mask][end] = 1;
				if (!dp[mask][end]) continue;
				if (mask != (1 << fone) + (1 << end))
					ans += dp[mask][end] * g[end][fone];
				for (int to = fone + 1; to < n; ++to)
					if (!(mask & (1 << to)))
						dp[mask + (1 << to)][to] += dp[mask][end] * g[end][to];
			}
	}
	cout << ans / 2 << endl;
	return exit_scs;
}


#ifdef pragma_comment_linker
#pragma comment(linker, "/STACK:16777216")
#endif

#define _CRT_SECURE_NO_WARNINGS SHUT_UP_BITCH
#define NDEBUG                  TROLOLO
#define null                    NULL
#define exit_scs                EXIT_SUCCESS

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
/*#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>*/

using namespace std;

#define all(v)                  (v).begin(), (v).end()
#define db(x)                   cerr << #x << '=' << (x) << "\n"
#define ft                      first
#define len(s)                  s.length()
#define maxV(type)              std::numeric_limits<type>::max()
#define minV(type)              std::numeric_limits<type>::min()
#define mp(a, b)                std::make_pair((a), (b))
#define pob()                   pop_back()
#define pof()                   pop_front()
#define pub(s)                  push_back((s))
#define puf(s)                  push_front((s))
#define sc                      second

typedef double                  f32;
typedef long double             f64;
typedef short int               i16;
typedef long long               i64;
typedef unsigned long long      u64;

const   long double             EPS = 0.00001;
const   long double             PI = 3.14159265358979323846;

inline void file_io(string in_file, string out_file, bool mark) {
	if (!mark) return;
	freopen(in_file.c_str(), "r", stdin);
	//freopen(out_file.c_str(), "w", stdout);
}

const int ML = (1 << 20);
i64 dp[ML][20];
bool g[20][20];

int main()
{
	file_io("input.in", "input.in", 0);
	cin.tie(null);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	int ML = (1 << (n + 1));
	for (int i = 0; i < 20; ++i)
		for (int j = 0; j < 20; ++j)
			g[i][j] = 0;
	for (int i = 0; i < ML; ++i)
		for (int j = 0; j < 20; ++j)
			dp[i][j] = 0;
	for (int i = 0; i < m; ++i) {
		int u, v;
		cin >> u >> v;
		g[u][v] = g[v][u] = 1;
	}
	i64 ans = 0;
	for (int mask = 1; mask < ML; ++mask) {
		int fone = 0;
		while (!(mask & (1 << fone)))
			++fone;
		for (int end = 1; end <= n; ++end)
			if (mask & (1 << end)) {
				if (mask == (1 << end))
					dp[mask][end] = 1;
				if (mask != (1 << fone) + (1 << end))
					ans += dp[mask][end] * g[end][fone];
				for (int to = fone + 1; to <= n; ++to)
					if (!(mask & (1 << to)))
						dp[mask + (1 << to)][to] += dp[mask][end] * g[end][to];
			}
	}
	cout << ans / 2 << endl;
	return exit_scs;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m, c;
int D[(1<<19)+3][21][21];
int C[23];
bool M[23][23];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    FWD(i,0,n) D[1<<i][i][i] = 1;
    FWD(m,0,1<<n)
        FWD(u,0,n)
            FWD(v,0,n){
                FWD(w,0,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][u][w] += D[m][u][v];
                if(M[u][v])
                    C[__builtin_popcount(m)] += D[m][u][v];
            }
    int r = 0;
    FWD(i,3,n+1)
        r += C[i] / i;
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m, c;
int D[(1<<19)+3][21];
bool M[23][23];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u][u] = 1;
        FWD(m,0,1<<n)
            FWD(v,u,n){
                FWD(w,u+1,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][u][w] += D[m][u][v];
                if(M[u][v])
                    r += D[m][u][v];
            }
    }
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
LL D[(1<<19)+3][21];
LL r;
bool M[21][21];
vector<int> in[(1<<19)+3], out[(1<<19)+3];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    FWD(m,0,1<<n)
        FWD(u,0,n)
            if(m&(1<<u))
                in[m].push_back(u);
            else
                out[m].push_back(u);
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n){
            for(int v : in[m]){
                for(int w : out[m])
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(__builtin_popcount(m) > 2 && M[u][v])
                    r += D[m][v];
            }
        }
    }
    cout << r/2 << endl;
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
int D[(1<<19)+3][21];
bool M[21][21];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n)
            FWD(v,u,n){
                FWD(w,u+1,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(__builtin_popcount(m) > 2 && M[u][v])
                    r += D[m][v];
            }
    }
    printf("%d\n", r/2);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m, c;
int D[(1<<19)+3][21];
bool M[23][23];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    FWD(u,0,n){
        printf("%d\n", u);
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n)
            FWD(v,u,n){
                FWD(w,u+1,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(M[u][v])
                    r += D[m][v];
                printf("%d %d %d\n", m, v, D[m][v]);
            }
    }
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
int D[(1<<19)+3][21];
bool M[21][21];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    FWD(u,0,n){
        printf("%d\n", u);
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n)
            FWD(v,u,n){
                FWD(w,u+1,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(M[u][v])
                    r += D[m][v];
                if(M[u][v])
                    printf("%d %d %d\n", m, v, D[m][v]);
            }
    }
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
int D[(1<<19)+3][21];
bool M[21][21];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    vector<int> in, out;
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n){
            in.clear();
            out.clear();
            FWD(v,u,n) if(m&(1<<v)) in.push_back(v); else out.push_back(v);
            for(int v : in){
                for(int w : out)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(__builtin_popcount(m) > 2 && M[u][v])
                    r += D[m][v];
            }
        }
    }
    printf("%d\n", r/2);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m, c;
int D[(1<<19)+3][21];
bool M[23][23];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    int r = 0;
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n)
            FWD(v,u,n){
                FWD(w,u+1,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(M[u][v])
                    r += D[m][v];
            }
    }
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m, c;
int D[(1<<19)+3][21][21];
int C[23];
bool M[23][23];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    FWD(i,0,n) D[1<<i][i][i] = 1;
    FWD(m,0,1<<n)
        FWD(u,0,n)
            FWD(v,0,n)
                FWD(w,0,n)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][u][w] += D[m][u][v]
        if(M[u][v])
            C[__builtin_popcount(m)] += D[m][u][v];
    }
    int r = 0;
    FWD(i,3,n+1)
        r += C[i] / i;
    printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
LL D[(1<<19)+3][21];
LL r;
bool M[21][21];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    vector<int> in, out;
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<n){
            in.clear();
            out.clear();
            FWD(v,u,n) if(m&(1<<v)) in.push_back(v); else out.push_back(v);
            for(int v : in){
                for(int w : out)
                    if(M[v][w] && !(m&(1<<w)))
                        D[m|(1<<w)][w] += D[m][v];
                if(__builtin_popcount(m) > 2 && M[u][v])
                    r += D[m][v];
            }
        }
    }
    cout << r/2 << endl;
    return 0;
}


#include <bits/stdc++.h>
#define FWD(a,b,c) for(int a=(b); a<(c); ++a)
#define BCK(a,b,c) for(int a=(b); a>(c); --a)
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

int n, m;
LL D[(1<<19)+3][21];
LL r;
bool M[21][21];
vector<int> in[(1<<19)+3], out[(1<<19)+3];

int main(){
    scanf("%d %d", &n, &m);
    FWD(i,0,m){
        int a, b;
        scanf("%d %d", &a, &b);
        --a; --b;
        M[a][b] = M[b][a] = 1;
    }
    FWD(m,0,1<<n)
        FWD(u,0,n)
            if(m&(1<<u))
                in[m].push_back(u);
            else
                out[m].push_back(u);
    FWD(u,0,n){
        FWD(m,0,1<<n)
            FWD(v,0,n)
                D[m][v] = 0;
        D[1<<u][u] = 1;
        FWD(m,0,1<<(n-u))
            for(int v : in[m<<u]){
                for(int w : out[m<<u])
                    if(M[v][w] && !((m<<u)&(1<<w)))
                        D[(m<<u)|(1<<w)][w] += D[(m<<u)][v];
                if(__builtin_popcount(m) > 2 && M[u][v])
                    r += D[(m<<u)][v];
            }
    }
    cout << r/2 << endl;
    return 0;
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<bitset>
#include<iomanip>
#include<iostream>
#include<cmath>
using namespace std;
#define rep(i,x,y) for(i=x;i<=y;i++)
#define _rep(i,x,y) for(i=x;i>=y;i--)
#define REP(i,x,y) for(int i=(x);i<=(y);i++)
#define _REP(i,x,y) for(int i=(x);i>=(y);i--)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
#define pb push_back
#define IN insert
#define ER erase
#define BE begin()
#define ED end()
#define LB lower_bound
#define UB upper_bound
#define mp make_pair
#define fi first
#define se second
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)
#define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endl
template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
template<class T> inline void read(T&x,T&y){read(x);read(y);}
template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);}
inline char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;}

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;

int n,m,i,j,k,l,p;
ll f[20][1<<20],ans[20],E[20];
bool e[20][20];int cnt[1<<20],t[1<<20];
int main()
{
    //freopen("1.in","r",stdin);freopen("1.out","w",stdout);

    read(n,m);
    int x,y;rep(i,1,m)read(x,y),e[x][y]=e[y][x]=1;
    rep(i,1,n)rep(j,1,n)if(e[i][j])E[i]|=1<<(j-1);
    rep(i,0,n)t[1<<i]=i+1;
    int st;
rep(st,1,n)
{
    CL(f,0);
    f[st][1<<(st-1)]=1;
    int MS=(1<<n)-1;
    rep(i,1,MS)cnt[i]=cnt[i/2]+(i&1);
    REP(pos,0,MS)rep(i,1,n)if(f[i][pos])
    {
        if(e[i][st])ans[cnt[pos]]+=f[i][pos];

        for(int S2=(MS-pos)&E[i];S2;S2-=S2&-S2)
        {
            int j=t[S2&-S2];
            f[j][pos|(1<<(j-1))]+=f[i][pos];
        }
    }
}
    ll tot=0;rep(i,3,n)tot+=ans[i]/2/i;
    cout<<tot<<endl;

    return 0;
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<bitset>
#include<iomanip>
#include<iostream>
#include<cmath>
using namespace std;
#define rep(i,x,y) for(i=x;i<=y;i++)
#define _rep(i,x,y) for(i=x;i>=y;i--)
#define REP(i,x,y) for(int i=(x);i<=(y);i++)
#define _REP(i,x,y) for(int i=(x);i>=(y);i--)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
#define pb push_back
#define IN insert
#define ER erase
#define BE begin()
#define ED end()
#define LB lower_bound
#define UB upper_bound
#define mp make_pair
#define fi first
#define se second
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)
#define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endl
template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
template<class T> inline void read(T&x,T&y){read(x);read(y);}
template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);}
inline char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;}

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;

int n,m,i,j,k,l,p;
ll f[20][1<<20],ans[20];
bool e[20][20];int cnt[1<<20];
int main()
{
    //freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    read(n,m);
    int x,y;rep(i,1,m)read(x,y),e[x][y]=e[y][x]=1;
    int st;
rep(st,1,n)
{
    CL(f,0);
    f[st][1<<(st-1)]=1;
    int MS=(1<<n)-1;
    rep(i,1,MS)cnt[i]=cnt[i/2]+(i&1);
    REP(pos,0,MS)rep(i,1,n)if(f[i][pos])
    {
        if(e[i][st])ans[cnt[pos]]+=f[i][pos];
        rep(j,1,n)
        if(e[i][j])
        if((pos>>(j-1)&1)==0)
        f[j][pos|(1<<(j-1))]+=f[i][pos];
    }
}
    ll tot=0;rep(i,3,n)tot+=ans[i]/2/i;
    cout<<tot<<endl;

    return 0;
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<bitset>
#include<iomanip>
#include<iostream>
#include<cmath>
using namespace std;
#define rep(i,x,y) for(i=x;i<=y;i++)
#define _rep(i,x,y) for(i=x;i>=y;i--)
#define REP(i,x,y) for(int i=(x);i<=(y);i++)
#define _REP(i,x,y) for(int i=(x);i>=(y);i--)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
#define pb push_back
#define IN insert
#define ER erase
#define BE begin()
#define ED end()
#define LB lower_bound
#define UB upper_bound
#define mp make_pair
#define fi first
#define se second
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)
#define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endl
template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};
template<class T> inline void read(T&x,T&y){read(x);read(y);}
template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);}
inline char getc(){char c;for(c=getchar();c<=32;c=getchar());return c;}

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;

int n,m,i,j,k,l,p;
ll f[20][1<<20],ans[20],E[20];
bool e[20][20];int cnt[1<<20],t[1<<20];
int main()
{
    //freopen("1.in","r",stdin);freopen("1.out","w",stdout);

    read(n,m);
    int x,y;rep(i,1,m)read(x,y),e[x][y]=e[y][x]=1;
    rep(i,1,n)rep(j,1,n)if(e[i][j])E[i]|=1<<(j-1);
    rep(i,0,n)t[1<<i]=i+1;
    int st;
rep(st,1,n)
{
    CL(f,0);
    f[st][1<<(st-1)]=1;
    int MS=(1<<n)-1;
    rep(i,1,MS)cnt[i]=cnt[i/2]+(i&1);
    REP(pos,0,MS)rep(i,st,n)if(f[i][pos])
    {
        if(e[i][st])ans[cnt[pos]]+=f[i][pos];
        for(int S2=(MS-pos)&E[i];S2;S2-=S2&-S2)
        {
            int j=t[S2&-S2];
            if(j>st)f[j][pos|(1<<(j-1))]+=f[i][pos];
        }
    }
}
    ll tot=0;rep(i,3,n)tot+=ans[i]/2;
    cout<<tot<<endl;

    return 0;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <cmath>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <cstring>
using namespace std;
#define ll long long

ll dp[1 << 19][19];
bool g[19][19];

int cnt(int h){
	int ans = 0;
	for (int i = 0; i < 32; i++)
		if (h & (1 << i))ans++;
	return ans;
}
int main(){
	int n, m, u, v;
	cin >> n >> m;
	for (int i = 0; i < m; i++){
		cin >> u >> v;
		u--; v--;
		g[u][v] = 1;
		g[v][u] = 1;
	}
	ll ans = 0;
	for (int u = 2; u < n; u++){
		int L = 1 << u;
		dp[L][u] = 1;
		for (int h = L; h < 2 * L; h++){
			for (int i = 0; i <= u; i++){
				if (dp[h][i]){
					for (int v = 0; v < u; v++){
						if (g[v][i] && !(h & 1 << v))
							dp[h | 1 << v][v] += dp[h][i];
					}
				}
			}
		}
		for (int h = L; h < 2 * L; h++){
			for (int i = 0; i < u; i++){
				if (g[i][u] && (h & 1 << i) && cnt(h) >= 3)
					ans += dp[h][i];
			}
		}
	}

	cout << ans / 2 << endl;

	cin >> n;
	return 0;
}