use std::io::*;
use std::str::FromStr;
use std::collections::BinaryHeap;

struct Graph {
    node: usize,
    directed: bool,
    graph: Vec<Vec<(usize, i64)>>,
}

impl Graph {
    fn new(n: usize, flag: bool) -> Graph {
        Graph { node: n, directed: flag, graph: vec![vec![]; n] }
    }

    fn add_edge(&mut self, start_node: usize, end_node: usize, cost: i64) -> () {
        self.graph[start_node].push((end_node, cost));
        if !self.directed { self.graph[end_node].push((start_node, cost)); }
    }
    fn dijkstra(&self, start_node: usize) -> Vec<i64> {
        let mut dist = vec![std::i64::MAX; self.node];
        dist[start_node] = 0;

        let mut queue: BinaryHeap<(i64, usize)> = BinaryHeap::new();
        queue.push((0, start_node));

        while !queue.is_empty() {
            let (min_dist, idx) = queue.pop().unwrap();
            if dist[idx] < -min_dist {
                continue;
            }
            for &(to, weight) in &self.graph[idx] {
                let cost_cand = dist[idx] + weight;
                if dist[to] > cost_cand {
                    dist[to] = cost_cand;
                    queue.push((-cost_cand, to));
                }
            }
        }
        dist
    }
    fn dijkstra_max(&self, start_node: usize) -> Vec<i64> {
        let mut dist = vec![0; self.node];
        dist[start_node] = 0;

        let mut queue: BinaryHeap<(i64, usize)> = BinaryHeap::new();
        queue.push((0, start_node));

        while !queue.is_empty() {
            let (max_dist, idx) = queue.pop().unwrap();
            if dist[idx] < -max_dist {
                continue;
            }
            for &(to, weight) in &self.graph[idx] {
                let cost_cand = dist[idx] + weight;
                if dist[to] < cost_cand {
                    dist[to] = cost_cand;
                    queue.push((-cost_cand, to));
                }
            }
        }
        dist
    }
    fn cnt_all_visit_path(&self, start_node: usize) -> usize {
        let visited: Vec<bool> = (0..self.node).map(|_| false).collect();

        fn _solve(node: usize, cnt: &mut usize, graph: &Vec<Vec<(usize, i64)>>, visited: &Vec<bool>) {
            if node >= visited.len() {
                return;
            }
            if visited[node] {
                return;
            }
            let mut visited = visited.clone();
            visited[node] = true;

            if visited.clone().into_iter().skip(1).filter(|f| !f).count() == 0  {
                *cnt += 1;
                return;
            }

            for &(to, _) in &graph[node] {
                _solve(to, cnt, graph, &visited);
            }
        }

        let mut cnt = 0;
        _solve(start_node, &mut cnt, &self.graph, &visited);
        return cnt;
    }
}

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char) 
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn main() {
    let n: usize = read();
    let m: usize = read();

    let mut g = Graph::new(n+1, false);
    for _ in 0..m {
        let a: usize = read();
        let b: usize = read();
        g.add_edge(a, b, 1);
    }

    println!("{}", g.cnt_all_visit_path(1));
}


Measured memory_bytes: 4352