import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class D11 {

	static StreamTokenizer in;
	static PrintWriter out;
	
	static int nextInt() throws IOException {
		in.nextToken();
		return (int)in.nval;
	}
	
	static String nextString() throws IOException {
		in.nextToken();
		return in.sval;
	}

	public static void main(String[] args) throws IOException {
		in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		out = new PrintWriter(System.out);

		n = nextInt();
		m = nextInt();
		
		g = new boolean[n][n];
		for (int i = 0; i < m; i++) {
			int a = nextInt()-1, b = nextInt()-1;
			g[a][b] = g[b][a] = true;
		}
		
		long ans = 0;
		for (int i = n-1; i >= 0; i--) {
			long cur = solve(i);
			ans += cur;
		}
		
		out.println(ans/2);
		
		out.flush();
	}

	static int n, m;
	static boolean[][] g;
	
	static long solve(int v) {
		long[][] memo = new long[v][1 << v];
		
		for (int i = 0; i < v; i++)
			if (g[v][i])
				memo[i][1 << i] = 1;
		
		for (int mask = 1; mask < (1 << v); mask++)
			for (int i = 0; i < v; i++) if ((mask&(1 << i)) != 0)
				for (int j = 0; j < v; j++) if (g[i][j] && (mask&(1 << j)) == 0)
					memo[j][mask|(1 << j)] += memo[i][mask];
		
		long res = 0;
		for (int mask = 1; mask < (1 << v); mask++)
			for (int i = 0; i < v; i++)
				if (Integer.bitCount(mask) > 1 && g[v][i]) res += memo[i][mask];
		return res;
	}
}
