codeparrot/codecomplex huggingface dataset:
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.PrintWriter;
import java.util.Scanner;

public class D {

    public void run(Scanner in, PrintWriter out) {
        int n = in.nextInt();
        int[][] graph = new int[n][n];
        int m = in.nextInt();
        for (int i = 0; i < m; i++) {
            int x = in.nextInt() - 1;
            int y = in.nextInt() - 1;
            graph[x][y] = 1;
            graph[y][x] = 1;
        }
        long[][] dyn = new long[1 << n][n];
        for (int i = 0; i < n; i++) {
            dyn[1 << i][i] = 1;
        }
        long answer = 0;
        for (int mask = 1; mask < 1 << n; mask++) {
            int start = Integer.numberOfTrailingZeros(mask);
            for (int i = 0; i < n; i++) {
                if ((mask & (1 << i)) == 0) continue;
                for (int j = start + 1; j < n; j++) {
                    if (graph[i][j] > 0 && (mask & (1 << j)) == 0) {
                        dyn[mask + (1 << j)][j] += dyn[mask][i];
                    }
                }
                if (graph[i][start] > 0) {
                    answer += dyn[mask][i];
                }
            }
        }
        out.println((answer - m)/ 2);
    }

    public static void main(String[] args) {
        try (Scanner in = new Scanner(System.in);
             PrintWriter out = new PrintWriter(System.out)
        ) {
            new D().run(in, out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.util.*;
import java.io.*;

public class Main implements Runnable {
	private void solution() throws IOException {
		int n = in.nextInt();
		int m = in.nextInt();
		boolean[][] adj = new boolean[n][n];
		long res = 0;
		for (int i = 0; i < m; ++i) {
			int x = in.nextInt();
			int y = in.nextInt();
			adj[x - 1][y - 1] = true;
			adj[y - 1][x - 1] = true;
		}
		for (int i = 0; i < n; ++i) {
			for (int j = i + 1; j < n; ++j) {
				if (adj[i][j]) {
					--res;
				}
			}
		}
		long[][] dp = new long[1 << n][n];
		for (int i = 0; i < n; ++i) {
			for (int mask = 0; mask < (1 << (n - i)); ++mask) {
				for (int j = 0; j < n - i; ++j) {
					dp[mask][j] = 0;
				}
			}
			dp[0][0] = 1;
			for (int mask = 0; mask < (1 << (n - i)); ++mask) {
				for (int j = 0; j < n - i; ++j) {
					if (dp[mask][j] != 0) {
						for (int k = 0; k < n - i; ++k) {
							if (((mask >> k) & 1) == 0 && adj[j + i][k + i]) {
								dp[mask | (1 << k)][k] += dp[mask][j];
							}
						}
					}
				}
				if (((mask >> 0) & 1) != 0) {
					res += dp[mask][0];
				}
			}
		}
		out.println(res / 2);
	}

	public void run() {
		try {
			solution();
			in.reader.close();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	private class Scanner {
		BufferedReader reader;
		StringTokenizer tokenizer;

		public Scanner(Reader reader) {
			this.reader = new BufferedReader(reader);
			this.tokenizer = new StringTokenizer("");
		}

		public boolean hasNext() throws IOException {
			while (!tokenizer.hasMoreTokens()) {
				String next = reader.readLine();
				if (next == null) {
					return false;
				}
				tokenizer = new StringTokenizer(next);
			}
			return true;
		}

		public String next() throws IOException {
			hasNext();
			return tokenizer.nextToken();
		}

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

		public String nextLine() throws IOException {
			tokenizer = new StringTokenizer("");
			return reader.readLine();
		}

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

	public static void main(String[] args) throws IOException {
		new Thread(null, new Main(), "", 1 << 28).start();
	}
	PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	Scanner in = new Scanner(new InputStreamReader(System.in));
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.util.*;
import java.io.*;

public class Main implements Runnable {
	private void solution() throws IOException {
		int n = in.nextInt();
		int m = in.nextInt();
		boolean[][] adj = new boolean[n][n];
		long res = 0;
		for (int i = 0; i < m; ++i) {
			int x = in.nextInt();
			int y = in.nextInt();
			adj[x - 1][y - 1] = true;
			adj[y - 1][x - 1] = true;
		}
		final long[][] dp = new long[1 << n][n];
		for (int i = 0; i < n; ++i) {
			int Limit = 1 << (n - i);
			int nn = n - i;
			for (int mask = 0; mask < Limit; ++mask) {
				for (int j = 0; j < nn; ++j) {
					dp[mask][j] = 0;
				}
			}
			dp[0][0] = 1;
			for (int mask = 0; mask < Limit; ++mask) {
				if ((mask & 1) == 0) {
					for (int j = 0; j < nn; ++j) {
						if (dp[mask][j] != 0) {
							long am = dp[mask][j];
							for (int k = 0; k < nn; ++k) {
								if (((mask >> k) & 1) == 0 && adj[j + i][k + i]) {
									dp[mask | (1 << k)][k] += am;
								}
							}
						}
					}
				} else {
					res += dp[mask][0];
				}
			}
		}
		out.println((res - m) / 2);
	}

	public void run() {
		try {
			solution();
			in.reader.close();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	private class Scanner {
		BufferedReader reader;
		StringTokenizer tokenizer;

		public Scanner(Reader reader) {
			this.reader = new BufferedReader(reader);
			this.tokenizer = new StringTokenizer("");
		}

		public boolean hasNext() throws IOException {
			while (!tokenizer.hasMoreTokens()) {
				String next = reader.readLine();
				if (next == null) {
					return false;
				}
				tokenizer = new StringTokenizer(next);
			}
			return true;
		}

		public String next() throws IOException {
			hasNext();
			return tokenizer.nextToken();
		}

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

		public String nextLine() throws IOException {
			tokenizer = new StringTokenizer("");
			return reader.readLine();
		}

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

	public static void main(String[] args) throws IOException {
		new Thread(null, new Main(), "", 1 << 28).start();
	}
	PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	Scanner in = new Scanner(new InputStreamReader(System.in));
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.*;
import java.util.*;
public class D11 {
	static boolean[][] g;
	static int n, m;
public static void main(String[] args) throws IOException {
	input.init(System.in);
	PrintWriter out = new PrintWriter(System.out);
	n = input.nextInt();
	m = input.nextInt();
	g = new boolean[n][n];
	for(int i = 0; i<m; i++)
	{
		int a = input.nextInt()-1, b = input.nextInt()-1;
		g[a][b] = g[b][a] = true;
	}
	long res = 0;
	map = new HashMap<Integer, Long>();
	for(int i = n-1; i>=0; i--)
	{
		memo = new long[i+1][1<<(i+1)];
		for(long[] A : memo) Arrays.fill(A, -1);
		res += count(i, i, 1<<i)/2;
	}
	out.println(res);
	out.close();
}
static long[][] memo;
static HashMap<Integer, Long> map;
static long count(int at, int start, int mask)
{
	if(memo[at][mask] != -1) return memo[at][mask];
	int bits = Integer.bitCount(mask);
	if(at == start && bits > 2) return 1;
	long res = 0;
	for(int i = 0; i<=start; i++)
	{
		if(!g[at][i]) continue;
		if(i != start && (mask & (1<<i)) > 0) continue;
		if(i == start && bits <= 2) continue;
		res += count(i, start, mask | (1<<i));
	}
	return memo[at][mask] = res;
}

public static class input {
	static BufferedReader reader;
	static StringTokenizer tokenizer;

	static void init(InputStream input) {
		reader = new BufferedReader(new InputStreamReader(input));
		tokenizer = new StringTokenizer("");
	}

	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens())
			tokenizer = new StringTokenizer(reader.readLine());
		return tokenizer.nextToken();
	}

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

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

	static long nextLong() throws 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 = first ; 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 && judge(i) ) {
							res += dp[i][j];
						}
						if ( (i&(1<<k))==0 ) {
							dp[i|(1<<k)][k] += dp[i][j];
						}
					}
				}
			}
			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.util.Scanner;

public class Hello {
		public static void main(String[] args){			
			Scanner scan = new Scanner(System.in);
			int n = scan.nextInt();
			int m = scan.nextInt();
			boolean[][] graph = new boolean[n][n];
			
			for(int i = 0; i < m; i++) {
				int from = scan.nextInt() - 1;
				int to = scan.nextInt() - 1;
				graph[from][to] = graph[to][from] = true;
			}
			
			int max = 1 << n;
			long[][] dp = new long[max][n];
			
			for(int mask = 1; mask < max; mask++) {
				for(int i = 0; i < n; i++) {
					boolean existI = (mask & (1 << i)) > 0;
					if(Integer.bitCount(mask) == 1 && existI) {
						dp[mask][i] = 1;
					} else if(Integer.bitCount(mask) > 1 && existI && first(mask) != i) {
						long sum = 0; 
						for(int j = 0; j < n; j++) {
							if(graph[i][j]) sum += dp[mask ^ (1 << i)][j];
						}
						dp[mask][i] = sum;
					}
				}
			}
			
			long countCycles = 0;
			for(int mask = 7; mask < max; mask++) {
				for(int i = 0; i < n; i++) {
					if(Integer.bitCount(mask) >= 3 && graph[first(mask)][i]) {
						countCycles += dp[mask][i];
					}
				}
			}
			System.out.println(countCycles / 2);
		}
		
		
		public static int first(int mask) {
			int i = 0;
			while((mask & (1 << i++)) == 0);
			return i - 1; 
		}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
/**
 * Codeforces Beta Round #10
 * 
 * @author ProjectYoung
 */

import java.util.Scanner;

public class CF11D {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int m = sc.nextInt();
    boolean[][] map = new boolean[n][n];
    long[][] dp = new long[1 << n][n];
    for (int i = 0; i < m; i++) {
      int a = sc.nextInt() - 1;
      int b = sc.nextInt() - 1;
      map[a][b] = map[b][a] = true;
      dp[(1 << a) + (1 << b)][Math.max(a, b)] = 1;
    }
    long ans = 0;
    for (int mask = 1; mask < (1 << n); mask++) {
      int lowbit = 0;
      for (; (mask & (1 << lowbit)) == 0; lowbit++);
      for (int i = lowbit + 1; i < n; i++) {
        if ((mask & (1 << i)) == 0) {
          continue;
        }
        for (int j = lowbit + 1; j < n; j++) {
          if ((mask & (1 << j)) == 0 || j == i) {
            continue;
          }
          if (map[i][j]) {
            dp[mask][i] += dp[mask ^ (1 << i)][j];
          }
        }
        if (map[lowbit][i]) {
          ans += dp[mask][i];
        }
      }
    }
    System.out.println((ans - m) / 2);
    sc.close();
  }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
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;
	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.util.*;
import java.io.*;

public class Main implements Runnable {
	private void solution() throws IOException {
		int n = in.nextInt();
		int m = in.nextInt();
		boolean[][] adj = new boolean[n][n];
		long res = 0;
		for (int i = 0; i < m; ++i) {
			int x = in.nextInt();
			int y = in.nextInt();
			adj[x - 1][y - 1] = true;
			adj[y - 1][x - 1] = true;
		}
		for (int i = 0; i < n; ++i) {
			for (int j = i + 1; j < n; ++j) {
				if (adj[i][j]) {
					--res;
				}
			}
		}
		for (int i = 0; i < n; ++i) {
			long[][] dp = new long[n - i][1 << (n - i)];
			dp[0][0] = 1;
			for (int mask = 0; mask < (1 << (n - i)); ++mask) {
				for (int j = 0; j < n - i; ++j) {
					if (dp[j][mask] != 0) {
						for (int k = 0; k < n - i; ++k) {
							if (((mask >> k) & 1) == 0 && adj[j + i][k + i]) {
								dp[k][mask | (1 << k)] += dp[j][mask];
							}
						}
					}
				}
				if (((mask >> 0) & 1) != 0) {
					res += dp[0][mask];
				}
			}
		}
		out.println(res / 2);
	}

	public void run() {
		try {
			solution();
			in.reader.close();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	private class Scanner {
		BufferedReader reader;
		StringTokenizer tokenizer;

		public Scanner(Reader reader) {
			this.reader = new BufferedReader(reader);
			this.tokenizer = new StringTokenizer("");
		}

		public boolean hasNext() throws IOException {
			while (!tokenizer.hasMoreTokens()) {
				String next = reader.readLine();
				if (next == null) {
					return false;
				}
				tokenizer = new StringTokenizer(next);
			}
			return true;
		}

		public String next() throws IOException {
			hasNext();
			return tokenizer.nextToken();
		}

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

		public String nextLine() throws IOException {
			tokenizer = new StringTokenizer("");
			return reader.readLine();
		}

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

	public static void main(String[] args) throws IOException {
		new Thread(null, new Main(), "", 1 << 28).start();
	}
	PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	Scanner in = new Scanner(new InputStreamReader(System.in));
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.*;
import java.util.StringTokenizer;

public class Main {

	private FastScanner in;
	private PrintWriter out;

	public void solve() throws IOException {
		int N = in.nextInt();
		int M = in.nextInt();

		int[][] edges = new int[N][N];
		for (int i = 0; i < M; i++) {
			int a = in.nextInt() - 1;
			int b = in.nextInt() - 1;
			edges[a][b] = 1;
			edges[b][a] = 1;
		}

		int globalCountMasks = 1 << N;
		int[][] masks = new int[N + 1][];
		int[] countMasks = new int[N + 1];
		for (int i = 0; i <= N; i++) {
			masks[i] = new int[combinations(N, i)];
		}
		for (int i = 0; i < globalCountMasks; i++) {
			int c = countBit1(i);
			masks[c][countMasks[c]] = i;
			countMasks[c]++;
		}

		long globalCountCycles = 0;
		long[][] count = new long[globalCountMasks][N];

		for (int a = 0; a < N - 2; a++) {
			int aBit = 1 << a;
			count[aBit][a] = 1;
			long countCycles = 0;
			for (int i = 2; i <= N; i++) {
				for (int m = 0; m < countMasks[i]; m++) {
					int mask = masks[i][m];
					if ((mask & aBit) == 0)
						continue;
					if ((mask & (aBit - 1)) > 0)
						continue;
					count[mask][a] = 0;
					for (int v = a + 1; v < N; v++) {
						int vBit = 1 << v;
						if ((mask & vBit) == 0)
							continue;
						count[mask][v] = 0;
						for (int t = a; t < N; t++) {
							if ((mask & (1 << t)) == 0 || t == v
									|| edges[v][t] == 0)
								continue;
							count[mask][v] += count[mask ^ vBit][t];
						}
						if (edges[a][v] == 1 && mask != (aBit | vBit)) {
							countCycles += count[mask][v];
						}
					}
				}
			}
			globalCountCycles += countCycles / 2;
		}

		out.println(globalCountCycles);
	}

	private int countBit1(int k) {
		int c = 0;
		while (k > 0) {
			c += k & 1;
			k >>= 1;
		}
		return c;
	}

	private int combinations(int n, int k) {
		if (k > n || k < 0) {
			throw new IllegalArgumentException();
		}
		int r = 1;
		for (int i = 1; i <= k; i++) {
			r = r * (n + 1 - i) / i;
		}
		return r;
	}

	public void run() {
		try {
			in = new FastScanner(System.in);
			out = new PrintWriter(System.out);
			solve();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class FastScanner {

		BufferedReader br;
		StringTokenizer st;

		FastScanner(InputStream is) {
			br = new BufferedReader(new InputStreamReader(is));
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

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

	public static void main(String[] arg) {
		new Main().run();
	}
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.*;
import java.util.*;

public class Template implements Runnable {
    private void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();
        boolean[][] g = new boolean[n][n];
        for (int i = 0; i < m; ++i) {
            int a = nextInt() - 1;
            int b = nextInt() - 1;
            g[a][b] = true;
            g[b][a] = true;
        }
        /*for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                g[i][j] = true;*/
        long[] am = new long[n + 1];
        long[][] ways = new long[1 << (n - 1)][n];
        for (int start = 0; start < n; ++start) {
            for (int mask = 0; mask < (1 << (n - start - 1)); ++mask)
                for (int last = start; last < n; ++last) {
                    ways[mask][last - start] = 0;
                }
            ways[1 >> 1][0] = 1;
            for (int mask = 1; mask < (1 << (n - start)); mask += 2) {
                int cnt = 0;
                int tmp = mask;
                while (tmp > 0) {
                    ++cnt;
                    tmp = tmp & (tmp - 1);
                }
                for (int last = start; last < n; ++last)
                    if (ways[mask >> 1][last - start] > 0) {
                        long amm = ways[mask >> 1][last - start];
                        for (int i = start; i < n; ++i)
                            if ((mask & (1 << (i - start))) == 0 && g[last][i]) {
                                ways[(mask | (1 << (i - start))) >> 1][i - start] += amm;
                            }
                        if (g[last][start])
                            am[cnt] += ways[mask >> 1][last - start];
                    }
            }
        }
        long res = 0;
        for (int cnt = 3; cnt <= n; ++cnt) {
            if (am[cnt] % (2) != 0)
                throw new RuntimeException();
            res += am[cnt] / (2);
        }
        writer.println(res);
    }


    public static void main(String[] args) {
        new Template().run();
    }

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

    public void run() {
        try {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
            writer = new PrintWriter(System.out);
            solve();
            reader.close();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

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

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

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

    String nextToken() throws IOException {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(reader.readLine());
        }
        return tokenizer.nextToken();
    }
}
// Problem: 11_D. A Simple Task
// Time complexity: np
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {

	private int n;
	private int m;
	private boolean[][] g;
	private long[][] dp;
	private int[] count;
	private int[] first;

	private void solve() throws IOException {
		n = nextInt();
		m = nextInt();

		g = new boolean[n][n];
		for (int i = 0; i < m; i++) {
			int a = nextInt() - 1;
			int b = nextInt() - 1;
			g[a][b] = true;
			g[b][a] = true;
		}

		count = new int[1 << n];
		first = new int[1 << n];
		dp = new long[1 << n][n];
		for (int mask = 0; mask < (1 << n); mask++) {
			count[mask] = bitCount(mask);
			for (int i = 0; i < n; i++) {
				if (bit(i, mask) == 1) {
					first[mask] = i;
					break;
				}
			}
		}

		for (int mask = 0; mask < (1 << n); mask++) {
			for (int i = 0; i < n; i++) {
				if ((count[mask] == 1) && (bit(i, mask) == 1)) {
					dp[mask][i] = 1;
				} else {
					for (int j = 0; j < n; j++) {
						if (g[j][i] && (count[mask] > 1) && (bit(i, mask) == 1)
								&& (first[mask] != i)) {
							dp[mask][i] += dp[mask ^ (1 << i)][j];
						}
					}
				}
			}
		}

		long ans = 0;
		for (int i = 0; i < n; i++) {
			for (int mask = 0; mask < (1 << n); mask++) {
				if ((count[mask] >= 3) && (first[mask] != i)
						&& (g[i][first[mask]])) {
					ans += dp[mask][i];
				}
			}
		}

		if (ans % 2 != 0) {
			throw new RuntimeException("SHIT!!!");
		}
		out.println(ans / 2);
	}

	private final int bit(int i, int mask) {
		return (mask & (1 << i)) != 0 ? 1 : 0;
	}

	private final int bitCount(int mask) {
		int ret = 0;
		while (mask != 0) {
			ret++;
			mask -= mask & (-mask);
		}
		return ret;
	}

	private BufferedReader in;
	private PrintWriter out;
	private StringTokenizer st;

	private Main() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		eat("");
		solve();
		in.close();
		out.close();
	}

	private void eat(String s) {
		st = new StringTokenizer(s);
	}

	String next() throws IOException {
		while (!st.hasMoreTokens()) {
			String line = in.readLine();
			if (line == null) {
				return null;
			}
			eat(line);
		}
		return st.nextToken();
	}

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

	public static void main(String[] args) throws IOException {
		new Main();
	}

}