// 問題: https://atcoder.jp/contests/abc054/tasks/abc054_c
// This template is based on Mr. tonymontaro's template (https://atcoder.jp/users/tonymontaro).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.StringTokenizer;

// For flatten() required Java8
import java.util.stream.Stream;
import java.util.stream.IntStream;

import java.util.Queue;
import java.util.ArrayDeque;

import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    static PrintWriter out;
    static CF_Reader in;

    static int N;

    // TODO: 配列の0初期化
    static int[][] adjacents;

    static int[] visited;

    static int ans = 0;

    public static void main(String[] args) throws IOException {
        out = new PrintWriter(new OutputStreamWriter(System.out));
        in = new CF_Reader();
        StringBuilder result = new StringBuilder();

        // Start: int型の整数N Mを取得する
        // // N M 形式
        // int N = in.intNext();
        // int M = in.intNext();
        //[補足]
        // N M
        // A B 形式だと
        N = in.intNext();
        int M = in.intNext();
        adjacents = new int[N][N];
        visited = new int[N];
        visited[0] = 1;
        // int A = in.intNext();
        // int B = in.intNext();
        // End: int型の整数N Mを取得する

        for (int i = 0; i < N; i++) {
          for (int j = 0; j < N; j++) {
            adjacents[i][j] = 0;
          }
        }

        // TODO: 無向グラフの表現方法
        for (int i = 0; i < M; i++) {
          int a = in.intNext();
          int b = in.intNext();
          adjacents[a - 1][b - 1] = 1;
          adjacents[b - 1][a - 1] = 1;
        }

        // for (int i = 0; i < N; i++) {
        //   for (int j = 0; j < N; j++) {
        //     out.print(adjacents[i][j]);
        //     out.print(" ");
        //   }
        //   out.println();
        // }

        dfs(0);
        result.append(ans);

        // Start: int型の整数Nと配列Aを取得する
        // // N
        // // A1 A2 A3... AN 形式
        // int n = in.intNext();
        // int[] A = in.nextIntArray(n);
        // End: int型の整数Nと配列Aを取得する

        // Start: Char型の文字をInt型に変換する
        // Integer.parseInt(String.valueOf(charText))
        // End: Char型の文字をInt型に変換する

        // Start: 文字列を1文字ずつ出力する
        // String text = in.next();
        // char[] work = new char[text.length()];
        // for(int i = 0; i < text.length(); i++){
        //   work[i] = text.charAt(i); // Char型の文字
        //   out.println(work[i]);
        // }
        // End: 文字列を1文字ずつ出力する

        // Start: 配列の定義
        // int[] a = new int[N];
        // int[][] b = new int[N][M];
        // End: 配列の定義

        // Start: キューの定義
        // Queue<int[]> queue = new ArrayDeque<int[]>();
        // Start: キューの定義

        // Start: リストのリスト
        // @SuppressWarnings("unchecked")
        // List<Integer>[] adjacents = new ArrayList[N];
        // Start: リストのリスト

        // Start: forEach文
        // for (int elem: elements) {
        // }
        // Start: forEach文

        out.println(result);

        out.close();
    }

    public static void dfs(int node) {
      int sum = 0;
      for(int i : visited) {
          // out.print(i);
          // out.print(" ");
          sum += i;
      }
      // out.println();
      if (sum == N) {
        ans++;
        return;
      }

      // out.println(node);

      for (int i = 0; i < N; i++) {
        if (adjacents[node][i] == 1 && visited[i] == 0) {
          int nextNode = i;
          visited[nextNode] = 1;
          dfs(nextNode);
          visited[nextNode] = 0;
        }
      }
    }

    public static int[] flatten(int[][] arr) {
       return Stream.of(arr)
          .flatMapToInt(row -> IntStream.of(row))
          .toArray();
    }

    public static int maxIntValueFromArray(int[] array) {

        int intMax = array[0];

        for (int i = 1; i < array.length; i++ ) {
            if(intMax < array[i]) {
                intMax = array[i];
            }
        }
        return intMax;
    }

    public static int minIntValueFromArray(int[] array) {

        int intMin = array[0];

        for (int i = 1; i < array.length; i++ ) {
            if(intMin > array[i]) {
                intMin = array[i];
            }
        }
        return intMin;
    }

    static class CF_Reader {
        BufferedReader br;
        StringTokenizer st;

        public CF_Reader() throws IOException {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

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

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

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

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

        char charNext() throws IOException {
            return next().charAt(0);
        }

        public int[] nextIntArray(final int n) throws IOException {
            final int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = intNext();
            return a;
        }

        public long[] nextLongArray(final int n) throws IOException {
            final long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = longNext();
            return a;
        }

        String line() throws IOException {
            return br.readLine().trim();
        }
    }
}

Measured memory_bytes: 21972