source_code: 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;
  	}
  }
  