codeparrot/codecomplex huggingface dataset:
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

import javax.sound.midi.Synthesizer;


public class Main {
	

	static int V;
	static ArrayList<Integer> adjList [];
	
	static int first(int a){
	    int idx = 0;
	    while (a > 0 && (a & 1) == 0) {
	        idx++;
	        a>>=1;
	    }
	    return idx;
	}
	static long Number_Of_Simple_Cycles () { // Time Complexity O(2 ^ n  * n ^ 2)
		long dp [][] = new long[1 << V][V];
		
		for (int i = 0 ; i < V ; ++i)
			dp[1 << i][i] = 1;
		
		for (int mask = 1 ; mask < 1 << V ; ++mask) {
				if (Integer.bitCount(mask) <= 1) continue;
				for (int current = 0 ; current < V ; ++current) {
					if (((1 << current) & mask) == 0) continue;
					
					for (int last : adjList[current])
						if (current != first(mask))
							{
								dp[mask][current] += dp[mask ^ (1 << current)][last];
							}
				}
		}
		
		long ans = 0 ;
		int allVisited = (1 << V) - 1;
		for (int mask = 1 ; mask < 1 << V ; ++mask) {
			if (Integer.bitCount(mask) < 3) continue;
			for (int u = 0 ; u < V ; ++u) {
				if (adjList[u].contains(first (mask)))
					ans += dp[mask][u];
			}
		}
		return ans >> 1;
	}
	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		PrintWriter out = new PrintWriter(System.out);
		V = sc.nextInt();
		adjList = new ArrayList[V];
		for (int i = 0 ; i < V ; ++i) adjList[i] = new ArrayList<>();
		int E = sc.nextInt();
		while (E -- > 0) {
			int v = sc.nextInt() - 1;
			int u = sc.nextInt() - 1;
			adjList[v].add(u);
			adjList[u].add(v);
		}
		out.print(Number_Of_Simple_Cycles());
		out.flush(); 
		out.close();
	}

	

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if (x.charAt(0) == '-') {
				neg = true;
				start++;
			}
			for (int i = start; i < x.length(); i++)
				if (x.charAt(i) == '.') {
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				} else {
					sb.append(x.charAt(i));
					if (dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg ? -1 : 1);
		}

		public boolean ready() throws IOException {
			return br.ready();
		}

	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.util.*;

public class cf11d {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int m = in.nextInt();
		boolean[][] g = new boolean[n][n];
		boolean[] ok = new boolean[1<<n];
		int[] f = new int[1<<n];
		for(int i=1; i<(1<<n); i++) {
			ok[i] = Integer.bitCount(i)>=3;
			f[i] = first(i);
		}
		for(int i=0; i<m; i++) {
			int a = in.nextInt()-1;
			int b = in.nextInt()-1;
			g[a][b] = g[b][a] = true;
		}
		long[][] dp = new long[n][1<<n];
		for(int i=0; i<n; i++)
			dp[i][1<<i] = 1;
		for(int i=1; i<(1<<n); i++)
			for(int j=0; j<n; j++)
				for(int k=f[i]+1; k<n; k++)
					if((i&(1<<k)) == 0 && g[j][k])
						dp[k][i^(1<<k)] += dp[j][i];
		long ret = 0;
		for(int i=1; i<(1<<n); i++)
			for(int j=0; j<n; j++)
				if(ok[i] && j != f[i])
					ret += g[j][f[i]]?dp[j][i]:0;
		System.out.println(ret/2);
	}
	static int first(int x) {
		int ret = 0;
		while(x%2==0) {
			x/=2;
			ret++;
		}
		return ret;
	}
}

/*

19 171
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 12
2 13
2 14
2 15
2 16
2 17
2 18
2 19
3 4
3 5
3 6
3 7
3 8
3 9
3 10
3 11
3 12
3 13
3 14
3 15
3 16
3 17
3 18
3 19
4 5
4 6
4 7
4 8
4 9
4 10
4 11
4 12
4 13
4 14
4 15
4 16
4 17
4 18
4 19
5 6
5 7
5 8
5 9
5 10
5 11
5 12
5 13
5 14
5 15
5 16
5 17
5 18
5 19
6 7
6 8
6 9
6 10
6 11
6 12
6 13
6 14
6 15
6 16
6 17
6 18
6 19
7 8
7 9
7 10
7 11
7 12
7 13
7 14
7 15
7 16
7 17
7 18
7 19
8 9
8 10
8 11
8 12
8 13
8 14
8 15
8 16
8 17
8 18
8 19
9 10
9 11
9 12
9 13
9 14
9 15
9 16
9 17
9 18
9 19
10 11
10 12
10 13
10 14
10 15
10 16
10 17
10 18
10 19
11 12
11 13
11 14
11 15
11 16
11 17
11 18
11 19
12 13
12 14
12 15
12 16
12 17
12 18
12 19
13 14
13 15
13 16
13 17
13 18
13 19
14 15
14 16
14 17
14 18
14 19
15 16
15 17
15 18
15 19
16 17
16 18
16 19
17 18
17 19
18 19

*/
// Problem: 11_D. A Simple Task
// Time complexity: np
//package round11;


import java.io.BufferedOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Scanner;

public class D {
	private Scanner in;
	private PrintWriter out;
	
	private boolean[][] g;
	
	public void solve()
	{
		n = ni();
		int m = ni();
		g = new boolean[n][n];
		for(int i = 0;i < m;i++){
			int f = ni();
			int t = ni();
			g[f-1][t-1] = true;
			g[t-1][f-1] = true;
		}
		
		long ret = 0L;
		cache = new long[20 << 19];
		for(int i = 0;i < n;i++){
			start = i;
			ret += rec(1 << start, i, 0);
		}
		out.println(ret/2);
	}
	
	private long[] cache;
	private int n;
	private int start;
	
	private long rec(int passed, int cur, int depth)
	{
		int code = cur << 19 | passed;
		if(cache[code] != 0)return cache[code];
		long ret = 0L;
		
		if(g[cur][start] && depth >= 2)ret++;
		for(int i = start + 1;i < n;i++){
			if((passed & (1 << i)) == 0 && g[cur][i]){
				ret += rec(passed | (1 << i), i, depth + 1);
			}
		}
		
		cache[code] = ret;
		return ret;
	}
	
	public void run() throws Exception
	{
//		int m = 19;
//		StringBuilder sb = new StringBuilder();
//		sb.append(m + " ");
//		sb.append((m*(m-1)/2) + " ");
//		for(int i = 1;i <= m;i++){
//			for(int j = i + 1;j <= m;j++){
//				sb.append(i + " " + j + "\n");
//			}
//		}
//		
//		in = new Scanner(new StringReader(sb.toString()));
//		in = new Scanner(new StringReader("4 6 1 2 1 3 1 4 2 3 2 4 3 4"));
		in = new Scanner(System.in);
		System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
		out = new PrintWriter(System.out);
		
//		int n = in.nextInt();
		int n = 1;
		for(int i = 1;i <= n;i++){
			long t = System.currentTimeMillis();
			solve();
			out.flush();
			System.err.printf("%04d/%04d %7d%n", i, n, System.currentTimeMillis() - t);
		}
	}
	
	
	public static void main(String[] args) throws Exception
	{
		new D().run();
	}
	
	private int ni() { return Integer.parseInt(in.next()); }
	private static void tr(Object... o) { System.out.println(o.length == 1 ? o[0] : Arrays.toString(o)); }
	private void tra(int[] a) {System.out.println(Arrays.toString(a));}
	private void tra(int[][] a)
	{
		for(int[] e : a){
			System.out.println(Arrays.toString(e));
		}
	}
	
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class B {
    static int first(int n)
    {
	int res = 0;
	while(n > 0 && (n & 1) == 0){
	    n >>= 1;
	    res++;
	}
	return res;
    }
    public static void main(String[] args) throws Exception
    {
	Scanner bf = new Scanner(System.in);
	PrintWriter out = new PrintWriter(System.out);
	int n = bf.nextInt(), m = bf.nextInt();
	ArrayList<Integer> [] adjList = new ArrayList[n];
	for (int i = 0; i < adjList.length; i++)
	{
	    adjList[i] = new ArrayList<Integer>();
	}
	for (int i = 0; i < m; i++)
	{
	    int u = bf.nextInt()-1, v = bf.nextInt()-1;
	    adjList[u].add(v);
	    adjList[v].add(u);
	}
	long [][] memo = new long[(1<<n)][n];
	for (int i = 0; i < n; i++)
	{
	    memo[1<<i][i] = 1;
	}
	long ans = 0;
	for (int i = 1; i < 1<<n; i++)
	{
	    if(Integer.bitCount(i) == 1) continue;
	    for (int j = 0; j < n; j++)
	    {
		if((i & (1<<j)) == 0 || j == first(i)) continue;
		for(int v:adjList[j])
		    memo[i][j] += memo[i^(1<<j)][v];
	    }
	}
	for (int i = 1; i < 1<<n; i++)
	{
	    if(Integer.bitCount(i) < 3) continue;
	    int t = first(i);
	    for (int j = 0; j < n; j++)
	    {
		if(adjList[j].contains(t))
		    ans += memo[i][j];
	    }
	}
	out.println(ans/2);
	out.flush();
	out.close();
    }

    static class Scanner {
	StringTokenizer st;
	BufferedReader br;

	public Scanner(InputStream s)
	{
	    br = new BufferedReader(new InputStreamReader(s));
	}

	public Scanner(FileReader fileReader)
	{
	    br = new BufferedReader(fileReader);
	}

	public String next() throws IOException
	{
	    while (st == null || !st.hasMoreTokens())
		st = new StringTokenizer(br.readLine());
	    return st.nextToken();
	}

	public int nextInt() throws IOException
	{
	    return Integer.parseInt(next());
	}

	public long nextLong() throws IOException
	{
	    return Long.parseLong(next());
	}

	public String nextLine() throws IOException
	{
	    return br.readLine();
	}

	public boolean ready() throws IOException
	{
	    return br.ready();
	}
    }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;


public class Main {

	static long[][] memo;
	static boolean[][] adjMat;
	static int N, endNode;
	static ArrayList<Integer>[] bits;
	
	static long dp(int idx, int msk)	//complexity = N * 2^(N + 1)
	{	
		if(memo[idx][msk] != -1)
			return memo[idx][msk];
		long ret = adjMat[idx][endNode] ? 1 : 0;
		for(int i = 0, sz = bits[msk].size(); i < sz; ++i)
		{
			int j = bits[msk].get(i);
			if(j > endNode)
				break;
			if(adjMat[idx][j])
				ret += dp(j, msk | 1 << j);
		}
		return memo[idx][msk] = ret;
	}
	
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);

		N = sc.nextInt();
		adjMat = new boolean[N][N];
		
		bits = new ArrayList[1 << N];
		for(int i = 0; i < 1 << N; ++i)
		{
			bits[i] = new ArrayList<>(1);
			for(int j = 0; j < N; ++j)
				if((i & 1 << j) == 0)
					bits[i].add(j);
		}
		int M = sc.nextInt();
		while(M-->0)
		{
			int u = sc.nextInt() - 1, v = sc.nextInt() - 1;
			adjMat[u][v] = adjMat[v][u] = true;
		}
		long ans = 0;
		for(int i = N; i > 1; --i)
		{
			memo = new long[i][1 << i];
			for(long[] x: memo)
				Arrays.fill(x, -1);
			ans += dp(endNode = i - 1, 1 << endNode);
		}
		for(int i = 0; i < N; ++i)
			for(int j = i + 1; j < N; ++j)
				if(adjMat[i][j])
					--ans;
		out.println(ans >> 1);
		out.flush();
		out.close();
	}
	 
	
	static class Scanner 
	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s){	br = new BufferedReader(new InputStreamReader(s));}

		public String next() throws IOException 
		{
			while (st == null || !st.hasMoreTokens()) 
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {return Integer.parseInt(next());}

		public long nextLong() throws IOException {return Long.parseLong(next());}

		public String nextLine() throws IOException {return br.readLine();}

		public double nextDouble() throws IOException { return Double.parseDouble(next()); }

		public boolean ready() throws IOException {return br.ready();} 
	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStreamReader;
import java.io.IOException;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author ATailouloute
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        QuickScanner in = new QuickScanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        public void solve(int testNumber, QuickScanner in, PrintWriter out) {
            int n = in.nextInt();
            int m = in.nextInt();
            boolean[][] is = new boolean[n][n];
            for (int i = 0; i < n; i++) {
                is[i][i] = true;
            }
            long[][] dp = new long[1 << n | 1][n];
            for (int i = 0; i < m; i++) {
                int u = in.nextInt() - 1;
                int v = in.nextInt() - 1;
                is[u][v] = is[v][u] = true;
                dp[(1 << u) + (1 << v)][v] = 1;
                dp[(1 << u) + (1 << v)][u] = 1;
            }
            int k = 0;
            long res = 0;
            for (int mask = 1; mask < 1 << n; ++mask) {
                boolean f = true;
                for (int i = 0; i < n; i++) {
                    if ((mask & (1 << i)) != 0 && dp[mask][i] == 0) {
                        if (f) {
                            f = false;
                            k = i;
                        } else {
                            for (int j = k + 1; j < n; j++) {
                                if ((mask & (1 << j)) != 0 && is[i][j]) {
                                    dp[mask][i] += dp[mask - (1 << i)][j];
                                }
                            }
                        }
                        if (is[k][i]) res += dp[mask][i];
                    }
                }
            }
            out.println(res >> 1);
        }

    }

    static class QuickScanner {
        BufferedReader br;
        StringTokenizer st;
        InputStream is;

        public QuickScanner(InputStream stream) {
            is = stream;
            br = new BufferedReader(new InputStreamReader(stream), 32768);
        }

        String nextToken() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(nextToken());
        }

    }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;

public class Main implements Runnable {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new Thread(new Main()).start();
	}

	public void run() {
		Locale.setDefault(Locale.US);
		try {
			run1();
		} catch (IOException e) {
			throw new RuntimeException();
		}
	}

	int nextInt(StreamTokenizer st) throws IOException {
		st.nextToken();
		return (int) st.nval;
	}

	private List<Integer> kmp(String x, String a) {
		String s = a + "$" + x;
		int[] oppa = new int[s.length()];
		oppa[0] = 0;
		int tmp = 0;
		List<Integer> res = new ArrayList<Integer>();
		for (int i = 1; i < s.length(); i++) {
			while (tmp != 0 && s.charAt(tmp) != s.charAt(i)) {
				// System.out.println(i + " " + tmp);
				tmp = oppa[tmp - 1];
			}
			if (s.charAt(tmp) == s.charAt(i))
				tmp++;
			oppa[i] = tmp;
			if (tmp == a.length()) {
				res.add(i - a.length() - a.length());
			}
		}
		return res;
	}

	double nextDouble(StreamTokenizer st) throws IOException {
		st.nextToken();
		return st.nval;
	}

	String nextLine(StreamTokenizer st) throws IOException {
		st.nextToken();
		return st.sval;
	}

	public void run1() throws IOException {
		Scanner sc = new Scanner(new InputStreamReader(System.in));
		// Scanner sc = new Scanner(new FileReader("input.txt"));
		int n = sc.nextInt();
		int m = sc.nextInt();
		boolean[][] arr = new boolean[n][n];
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			arr[a - 1][b - 1] = true;
			arr[b - 1][a - 1] = true;
		}
		long[][] res = new long[n][1 << n];
		for (int mask = 1; mask < (1 << n); mask++) {
			int min = -1;
			for (int i = 0; i < n; i++) {
				if ((mask & (1 << i)) != 0) {
					if (min == -1) {
						min = i;
						if (mask == (1 << min))
							res[min][mask] = 1;
					}
					for (int j = min + 1; j < n; j++)
						if ((mask & (1 << j)) == 0 && arr[i][j]) {
							res[j][mask | (1 << j)] += res[i][mask];
						}
				}
			}
		}
		long r = 0;
		for (int mask = 1; mask < (1 << n); mask++)
			if (Integer.bitCount(mask) != 2)
				for (int j = 0; j < n; j++) {
					int i = 0;
					while ((mask & (1 << i)) == 0)
						i++;
					if (arr[i][j])
						r += res[j][mask];
				}
		System.out.println(r / 2);
	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class D {
    static boolean[][] adj;
    static int n;
    static int first;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader();
        n = in.nextInt();
//       n = 19;?
        int m = in.nextInt();
        adj = new boolean[n][n];
//       for (int i = 0; i < n; i++) {
//       for (int j = 0; j < n; j++) {
//       adj[i][j] = true;
//       }
//       }
        dp = new long[1 << n][n];
        for (int i = 0; i < m; i++) {
            int f = in.nextInt() - 1;
            int t = in.nextInt() - 1;
            adj[f][t] = adj[t][f] = true;
        }

        boolean[] v = new boolean[1 << n];
        long res = 0;
        for (int f = 0; f < n; f++) {
            first = f;
            int cnt;
            for (int i = 0; i < 1 << n; i+=(1<<first))
                if ((i & (1 << first)) == 0)
                    for (int j = 0; j < n; j++)
                        dp[i][j] = -1;
            
            for (int i = 0; i < 1 << n; i+= (1<<first)) {
                cnt = Integer.bitCount(i);
                if ((i & (1 << first)) == 0 && !v[i | (1 << first)] && cnt > 1) {
                    v[i | (1 << first)] = true;
                    res += solve(i, first, cnt);
                }
            }
        }
        System.out.println(res / 2);
    }

    static long[][] dp;

    public static long solve(int msk, int lst, int cnt) {
        if (cnt == 0)
            return (adj[lst][first]) ? 1 : 0;
        if (dp[msk][lst] != -1)
            return dp[msk][lst];
        long res = 0;
        for (int i = 0; i < n; i++)
            if (adj[lst][i] && (msk & (1 << i)) > 0)
                res += solve(msk ^ (1 << i), i, cnt - 1);
        return dp[msk][lst] = res;
    }

    static class InputReader {
        BufferedReader in;
        StringTokenizer st;

        public InputReader() throws IOException {
            in = new BufferedReader(new InputStreamReader(System.in));
            st = new StringTokenizer(in.readLine());
        }

        public String next() throws IOException {
            while (!st.hasMoreElements())
                st = new StringTokenizer(in.readLine());
            return st.nextToken();
        }

        public int nextInt() throws NumberFormatException, IOException {
            return Integer.parseInt(next());
        }

        public long nextLong() throws NumberFormatException, IOException {
            return Long.parseLong(next());
        }
    }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while ( sc.hasNextInt() ) {
			int n = sc.nextInt();
			long m = sc.nextInt();
			boolean edge[][] = new boolean[n][n];
			long dp[][] = new long[1<<n][n];
			for ( long i = 1 ; i<=m ; ++i ) {
	 			int u = sc.nextInt();   
				int v = sc.nextInt();
				-- u;
				-- v;
				edge[u][v] = edge[v][u] = true;
			}
			for ( int i = 0 ; i<n ; ++i ) {
				dp[1<<i][i] = 1;
			}
			long res = 0;
			for ( int i = 1 ; i<(1<<n) ; ++i ) {
				int first = cal(i);
				for ( int j = 0 ; j<n ; ++j ) {
					if ( dp[i][j]==0 ) {
						continue;
					}
					for ( int k = first ; k<n ; ++k ) {
 						if ( j==k || !edge[j][k] ) {
							continue;
						}
						if ( k==first && (i&(1<<k))!=0 ) {
							res += dp[i][j];
						}
						if ( (i&(1<<k))==0 ) {
							dp[i|(1<<k)][k] += dp[i][j];
						}
					}
				}
			}
			res -= m;
			System.out.println(res/2);		
		}
	}
	public static int cal( int x ) {
		int ord = 0;
		while ( true ) {
			if ( (x&(1<<ord))!=0 ) {
				break;
			}
			++ ord;
		}
		return ord;
	}
	public static boolean judge( int x ) {
		int cnt = 0;
		while ( x>=1 ) {
			if ( (x&1)==1 ) {
				++ cnt;
			}
			x >>= 1;
		}
		return cnt >= 3;
	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;

/**
 * Created by Tejas on 18-10-2018.
 */
public class Main {

    static HashSet<Integer> adjList[];
    public static void main(String[]args)throws IOException{
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
        StringBuilder stringBuilder=new StringBuilder();

        String temp[]=bufferedReader.readLine().split(" ");
        int V=Integer.parseInt(temp[0]);
        int E=Integer.parseInt(temp[1]);
        adjList=new HashSet[V];
        for(int i=0;i<V;i++)
            adjList[i]=new HashSet<>();
        for(int i=0;i<E;i++){
            temp=bufferedReader.readLine().split(" ");
            int x=Integer.parseInt(temp[0])-1;
            int y=Integer.parseInt(temp[1])-1;
            adjList[y].add(x);
            adjList[x].add(y);

        }
        stringBuilder.append(solve(V)+"\n");
        System.out.println(stringBuilder);
    }

    private static long solve(int V) {

        long dp[][]=new long[(1<<V)][V];

        for(int i=0;i<V;i++)
            dp[(1<<i)][i]=1;
        for(int mask=1;mask<(1<<V);mask++){
            // HW starting at pos first and ending at j.
            int first = Integer.numberOfTrailingZeros(mask);
            for(int i=0;i<V;i++){
                if((mask&(1<<i))==0 || first==i) continue;
                for (int j = 0; j < V; j++)
                    if (adjList[i].contains(j) && (mask & (1<<j))!=0)
                        dp[mask][i] += dp[mask ^ (1 << i)][j];
            }
        }
        //Calculating simple cycles
        long count=0;
        for(int mask=1;mask<(1<<V);mask++) {
            int first = Integer.numberOfTrailingZeros(mask);
            if (Integer.bitCount(mask)>=3)
                for (int i = 0; i < V; i++) {
                    if(adjList[first].contains(i))
                        count+=dp[mask][i];
                }
        }
        return count/2;


    }
}