CodeEff/ECCO huggingface dataset:
# Original solution
import copy
import sys
sys.setrecursionlimit(10**7)
N, M = list(map(int, input().split()))
edges = [[] for _ in range(N)]
for _ in range(M):
    a, b = list(map(int, input().split()))
    edges[a - 1].append(b - 1)
    edges[b - 1].append(a - 1)
ans = 0
def dfs(start,path):
    next_path = copy.copy(path)
    global ans
    next_path.append(start)
    if len(next_path) == N:
        ans += 1
        return
    for i in edges[start]:
        if i not in next_path:
            dfs(i,next_path)
dfs(0,[])
print(ans)

# Optimized solution
def dfs(start,path):
    res = 0
    path.append(start)
    if len(path) == N:
        res += 1
        return res
    for i in graph[start]:
        if i not in path:
            res += dfs(i,path)
            path.pop()
    return res

N, M = list(map(int, input().split()))
graph = [[] for _ in range(N)]
for i in range(M):
    a, b = list(map(int, input().split()))
    graph[a-1].append(b-1)
    graph[b-1].append(a-1)
print((dfs(0,[])))
# Original solution
import sys
from itertools import permutations

def debug(x, table):
    for name, val in table.items():
        if x is val:
            print('DEBUG:{} -> {}'.format(name, val), file=sys.stderr)
            return None

cnt = 0

def dfs(N, Adj, p, pos, mask):
    global cnt

    if pos == N:
        for i in range(N - 1):
            if not Adj[p[i]][p[i + 1]]:
                break
        else:
            cnt += 1

        return None

    for i in range(N):
        if mask & (1 << i):
            p[pos] = i
            dfs(N, Adj, p, pos + 1, (mask ^ (1 << i)))

    return None

def solve():
    global cnt
    cnt = 0

    N, M = map(int, input().split())
    Adj = [[0]*N for i in range(N)]

    for i in range(M):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        Adj[a][b] = 1
        Adj[b][a] = 1

    p = list(range(N))
    dfs(N, Adj, p, 1, (2 << N) - 1 - 1)

    print(cnt)

if __name__ == '__main__':
    solve()


# Optimized solution
import sys
from itertools import permutations

def debug(x, table):
    for name, val in table.items():
        if x is val:
            print('DEBUG:{} -> {}'.format(name, val), file=sys.stderr)
            return None

def do_dp(N, Adj):
    univ = 2**N - 1
    dp = [[0]*N for i in range(univ + 1)]
    dp[1][0] = 1

    for S in range(2, univ + 1):
        for v in range(N):
            S2 = S & (univ ^ (1 << v))
            for u in range(N):
                if ((1 << u) & S2) and Adj[u][v]:
                    dp[S][v] += dp[S2][u]

    # debug(dp, locals())
    ans = sum(dp[univ][u] for u in range(1, N))

    return ans

def solve():
    N, M = map(int, input().split())
    Adj = [[0]*N for i in range(N)]

    for i in range(M):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        Adj[a][b] = 1
        Adj[b][a] = 1

    ans = do_dp(N, Adj)

    print(ans)

if __name__ == '__main__':
    solve()
# Original solution
import sys
from itertools import permutations

def debug(x, table):
    for name, val in table.items():
        if x is val:
            print('DEBUG:{} -> {}'.format(name, val), file=sys.stderr)
            return None

def do_dp(N, Adj):
    univ = 2**N - 1
    dp = [[0]*N for i in range(univ + 1)]
    dp[1][0] = 1

    for S in range(2, univ + 1):
        for v in range(N):
            S2 = S & (univ ^ (1 << v))
            for u in range(N):
                if ((1 << u) & S2) and Adj[u][v]:
                    dp[S][v] += dp[S2][u]

    # debug(dp, locals())
    ans = sum(dp[univ][u] for u in range(1, N))

    return ans

def solve():
    N, M = map(int, input().split())
    Adj = [[0]*N for i in range(N)]

    for i in range(M):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        Adj[a][b] = 1
        Adj[b][a] = 1

    ans = do_dp(N, Adj)

    print(ans)

if __name__ == '__main__':
    solve()


# Optimized solution
import sys

def debug(x, table):
    for name, val in table.items():
        if x is val:
            print('DEBUG:{} -> {}'.format(name, val), file=sys.stderr)
            return None

def do_dp(N, Adj):
    univ = 2**(N-1) - 1
    dp = [[0]*(N-1) for i in range(univ + 1)]

    for u in range(N - 1):
        if Adj[0][u+1]:
            dp[1<<u][u] = 1

    for S in range(univ + 1):
        for v in range(N - 1):
            S2 = S & (univ ^ (1 << v))
            for u in range(N):
                if ((1 << u) & S2) and Adj[u+1][v+1]:
                    dp[S][v] += dp[S2][u]

    # debug(dp, locals())
    ans = sum(dp[univ][u] for u in range(N - 1))

    return ans

def solve():
    N, M = map(int, input().split())
    Adj = [[0]*N for i in range(N)]

    for i in range(M):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        Adj[a][b] = 1
        Adj[b][a] = 1

    ans = do_dp(N, Adj)

    print(ans)

if __name__ == '__main__':
    solve()
# Original solution
# -*- coding: utf-8 -*-

from collections import deque

N, M = list(map(int, input().split()))
Ms = {i:set() for i in range(1, N + 1)}
for _ in range(M):
    a, b = list(map(int, input().split()))
    Ms[a].add(b)
    Ms[b].add(a)

all = set(range(1, N + 1))
q = deque()
q.append((1, [1]))

ans = 0
while q:
    n, v = q.popleft()
    if set(v) == all:
        ans += 1
        continue
    for to in Ms[n]:
        if not to in v:
            q.append((to, v + [to]))

print(ans)


# Optimized solution
N, M = list(map(int, input().split()))
G = [[] for _ in range(N)]
for _ in range(M):
    A, B = list(map(int, input().split()))
    G[A - 1].append(B - 1)
    G[B - 1].append(A - 1)

path, ans = [[0]], 0
while len(path) > 0:
    p = path.pop()
    if len(p) == N:
        ans += 1
    else:
        for g in G[p[-1]]:
            if not g in p:
                path.append(p + [g])

print(ans)
# Original solution
import itertools as it
import sys

N, M = list(map(int, input().split()))
if N==0 or M==0:
    print((0))
    sys.exit()
a=[]

for i in range(M):
    x,y=list(map(int,input().split()))
    a.append([x,y])
    a.append([y,x])

ans=0
for e in it.permutations(list(range(N))):
    if e[0]!=0:
        break
        
    count=1
    for j in range(N-1):
        if [e[j]+1,e[j+1]+1] in a:
            count*=1
        else:
            count*=0
            break
            
    ans+=count

print(ans)

# Optimized solution
import itertools as it
import sys

N, M = list(map(int, input().split()))

a=[]

for i in range(M):
    x,y=list(map(int,input().split()))
    a.append([x,y])
    a.append([y,x])

ans=0
for e in it.permutations(list(range(N))):
    if e[0]!=0:
        break
        
    count=1
    for j in range(N-1):
        if [e[j]+1,e[j+1]+1] in a:
            count*=1
        else:
            count*=0
            break
            
    ans+=count

print(ans)
# Original solution

n,m=list(map(int,input().split()))

edges=[[] for i in range(n)]

for i in range(m):
  s,t = list(map(int,input().split()))
  edges[s-1].append(t-1)
  edges[t-1].append(s-1)

cnt =[0]

def dfs(V,s):
  V[s]=1
  if sum(V)==n:
    cnt[0]+=1
  else:
    for adj in edges[s]:
      if V[adj] == 0:
        dfs(V[:adj] + [1] + V[adj + 1:], adj)
dfs([0] * n, 0)
print((cnt[0]))


# Optimized solution
n,m=list(map(int,input().split()))

edges=[[] for i in range(n)]

for i in range(m):
  s,t = list(map(int,input().split()))
  edges[s-1].append(t-1)
  edges[t-1].append(s-1)

cnt =0

V=[0]*n

def dfs(V,s):
  global cnt
  V=V[:]
  V[s]=1
  if sum(V)==n:
    cnt+=1
  else:
    for v in edges[s]:
      if V[v]==0:
        dfs(V,v)
  # print(V)
dfs(V,0)
print(cnt)
# Original solution
n,m=list(map(int,input().split()))

edges=[[] for i in range(n)]

for i in range(m):
  s,t = list(map(int,input().split()))
  edges[s-1].append(t-1)
  edges[t-1].append(s-1)

cnt =0

V=[0]*n

def dfs(V,s):
  global cnt
  V=V[:]
  V[s]=1
  if sum(V)==n:
    cnt+=1
  else:
    for v in edges[s]:
      if V[v]==0:
        dfs(V,v)
  # print(V)
dfs(V,0)
print(cnt)

# Optimized solution
n,m=list(map(int,input().split()))
edges=[[0]*n for i in range(n)]
for i in range(m):
  a,b=list(map(int,input().split()))
  edges[a-1].append(b-1)
  edges[b-1].append(a-1)

visited=[False]*n
count=0
def dfs(u,visited):
  global count
  visited=visited[:]
  visited[u]=True
  if all(visited):
    count+=1
    return
  for v in edges[u]:
    if not visited[v]:
      dfs(v,visited)
  return False

dfs(0,visited)
print(count)
# Original solution
import array
import itertools
from collections import defaultdict, deque


def log(s):
    # print("| " + str(s), file=sys.stderr)
    pass


def output(x):
    print(x, flush=True)


def input_ints():
    return map(int, input().split())


def solve():
    num_nodes, num_edges = tuple(input_ints())

    edges = [tuple(input_ints()) for _ in range(num_edges)]

    navigatility = defaultdict(lambda: [])

    for e in edges:
        navigatility[e[0]].append(e[1])
        navigatility[e[1]].append(e[0])

    queue = deque()
    queue.append([1])
    result = []

    while queue:
        path = queue.popleft()

        if len(path) == num_nodes:
            result.append(path)
        else:
            n = path[-1]

            for m in navigatility[n]:
                if m not in path:
                    queue.append(path + [m])

    return result


def main():
    print(len(solve()))


main()


# Optimized solution
import array
import itertools
from collections import defaultdict, deque


def log(s):
    # print("| " + str(s), file=sys.stderr)
    pass


def output(x):
    print(x, flush=True)


def input_ints():
    return map(int, input().split())


def solve():
    num_nodes, num_edges = tuple(input_ints())

    edges = [tuple(input_ints()) for _ in range(num_edges)]

    navigability = defaultdict(lambda: [])

    for e in edges:
        navigability[e[0]].append(e[1])
        navigability[e[1]].append(e[0])

    def solve1(path, result):
        if len(path) == num_nodes:
            result.append(path)
            return

        for m in navigability[path[-1]]:
            if m not in path:
                solve1(path + [m], result)

        return result

    return solve1([1], [])


def main():
    print(len(solve()))


main()
# Original solution
from itertools import permutations
N, M = list(map(int, input().split()))
edges = []

for i in range(M):
    a, b = list(map(int, input().split()))
    edges.append([a-1, b-1])

mat = [[0]*N for _ in range(N)]

for s, g in edges:
    mat[s][g] = 1
    mat[g][s] = 1


P = permutations(list(range(N)))
ans = 0
for route in P:
    if route[0] != 0:
        continue
    else:
        vis = 0
        for s, g in zip(route, route[1:]):
            if mat[s][g] == 1:
                vis += 1
                if vis == N-1:
                    ans += 1
                continue
            else:
                break
print(ans)


# Optimized solution
def bit_dp(N, Adj):
    dp = [[0]*N for i in range(1 << N)]
    #dp[{0},0] = 1

    dp[1][0] = 1

    for S in range(1 << N):
        for v in range(N):
            # v がSに含まれていないときはパス
            if (S & (1 << v)) == 0:
                continue

            #sub = S - {v}
            sub = S ^ (1 << v)

            for u in range(N):
                # sub に uが含まれていて、かつ uとvがへんで結ばれている
                if (sub & (1 << u)) and (Adj[u][v]):
                    dp[S][v] += dp[sub][u]
    ans = sum(dp[(1 << N) - 1][u] for u in range(1, N))
    return ans


def main():
    N, M = list(map(int, input().split()))
    Adj = [[False]*N for _ in range(N)]

    for _ in range(M):
        a, b = list(map(int, input().split()))
        Adj[a-1][b-1] = 1
        Adj[b-1][a-1] = 1
    ans = bit_dp(N, Adj)

    print(ans)


if __name__ == '__main__':
    main()
# Original solution
import itertools

N, M = list(map(int, input().split()))
adj_matrix = [[0]*N for _ in range(N)]

# 隣接行列を作る
for i in range(M):
    a, b = list(map(int, input().split()))
    adj_matrix[a-1][b-1] = 1
    adj_matrix[b-1][a-1] = 1

cnt = 0

for each in itertools.permutations(list(range(N))):
    if each[0] != 0:  # 始点は1でないといけないから
        break
    factor = 1
    for i in range(N-1):
        factor *= adj_matrix[each[i]][each[i+1]]
    cnt += factor

print(cnt)

# Optimized solution
N, M = list(map(int, input().split()))
adj_matrix = [[0]*N for _ in range(N)]

for i in range(M):
    a, b = list(map(int, input().split()))
    adj_matrix[a-1][b-1] = 1
    adj_matrix[b-1][a-1] = 1

def dfs(v, used):
    if not False in used:
        return 1

    ans = 0
    for i in range(N):
        if not adj_matrix[v][i]:
            continue
        if used[i]:
            continue
        used[i] = True
        ans += dfs(i, used)
        used[i] = False        
    return ans

used = [False] * N
used[0] = True
print((dfs(0, used)))
# Original solution
N, M = list(map(int, input().split()))
adj_matrix = [[0]*N for _ in range(N)]

for i in range(M):
    a, b = list(map(int, input().split()))
    adj_matrix[a-1][b-1] = 1
    adj_matrix[b-1][a-1] = 1

def dfs(v, used):
    if not False in used:
        return 1

    ans = 0
    for i in range(N):
        if not adj_matrix[v][i]:
            continue
        if used[i]:
            continue
        used[i] = True
        ans += dfs(i, used)
        used[i] = False        
    return ans

used = [False] * N
used[0] = True
print((dfs(0, used)))

# Optimized solution
N, M = list(map(int, input().split()))
g = [[] for i in range(N)]

for i in range(M):
  a, b = list(map(int, input().split()))
  g[a-1].append(b-1)
  g[b-1].append(a-1)

memo = {}
All_used = (1 << N) - 1

def dfs(v, used):
  if used == All_used:
    return 1
  key = (v, used)
  if key in memo:
    return memo[key]
  ans = 0
  for u in g[v]:
    if (used >> u) & 1 ==1:
      continue
    used ^= (1 << u)
    ans += dfs(u, used)
    used ^= (1 << u)
  memo[key] = ans
  return ans

print((dfs(0, 1)))
# Original solution
from collections import deque
from copy import deepcopy as dc
import sys

def main():
    input = sys.stdin.readline
    n, m = list(map(int, input().split()))
    ab = [list(map(int, input().split())) for i in range(m)]
    g = [[] for i in range(n+1)]
    for i in ab:
        g[i[0]].append(i[1])
        g[i[1]].append(i[0])
    que = deque()
    que.append([1,-1,0,set([1])])
    ans = 0
    while que:
        v, p, cnt, check = que.popleft()
        if cnt >= n - 1:
            if len(check) == n:
                ans += 1
            continue
        for nv in g[v]:
            if nv == p:
                continue
            a = dc(check)
            a.add(nv)
            que.append([nv, v, cnt+1, a])
    print(ans)

if __name__ == "__main__":
    main()


# Optimized solution
from collections import deque
from copy import copy as dc
import sys

def main():
    input = sys.stdin.readline
    n, m = list(map(int, input().split()))
    ab = [list(map(int, input().split())) for i in range(m)]
    g = [[] for i in range(n+1)]
    for i in ab:
        g[i[0]].append(i[1])
        g[i[1]].append(i[0])
    que = deque()
    que.append([1,-1,0,set([1])])
    ans = 0
    while que:
        v, p, cnt, check = que.popleft()
        if cnt >= n - 1:
            if len(check) == n:
                ans += 1
            continue
        for nv in g[v]:
            if nv == p:
                continue
            a = dc(check)
            a.add(nv)
            que.append([nv, v, cnt+1, a])
    print(ans)

if __name__ == "__main__":
    main()
# Original solution
from collections import deque
from copy import copy as dc
import sys

def main():
    input = sys.stdin.readline
    n, m = list(map(int, input().split()))
    ab = [list(map(int, input().split())) for i in range(m)]
    g = [[] for i in range(n+1)]
    for i in ab:
        g[i[0]].append(i[1])
        g[i[1]].append(i[0])
    que = deque()
    que.append([1,-1,0,set([1])])
    ans = 0
    while que:
        v, p, cnt, check = que.popleft()
        if cnt >= n - 1:
            if len(check) == n:
                ans += 1
            continue
        for nv in g[v]:
            if nv == p:
                continue
            a = dc(check)
            a.add(nv)
            que.append([nv, v, cnt+1, a])
    print(ans)

if __name__ == "__main__":
    main()


# Optimized solution
import sys
sys.setrecursionlimit(4100000)

def Dfs(G, v, n, visited):
    all_visited = True
  
    for i in range(n):
      if visited[i] == False:
        all_visited = False
 
    if all_visited:
        return 1
 
    ret = 0
 
    for i in range(n):
        if not G[v][i]:
            continue
        if visited[i]:
            continue
        visited[i] = True
        ret += Dfs(G, i, n, visited)
        visited[i] = False
 
    return ret

 
def main():
    input =  sys.stdin.readline
    n, m = list(map(int, input().split()))
    e = [list(map(int, input().split())) for i in range(m)]
    g = [[False for j in range(n)] for i in range(n)]
    for i, j in e:
        g[i-1][j-1] = True
        g[j-1][i-1] = True
    visited = [False for i in range(n)]
    visited[0] = True
    
    print((Dfs(g, 0, n, visited)))

if __name__ == "__main__":
    main()
# Original solution
from itertools import permutations
from copy import deepcopy

N,M = [int(i) for i in input().split()]
links  = [[int(i) for i in input().split()] for _ in range(M)]

ans = 0

for path in permutations(list(range(2,N+1))):
    l = deepcopy(links)
    p_node = 1
    for n_node in path:
        if sorted([p_node,n_node]) in l:
            l.pop(l.index(sorted([p_node,n_node])))
            p_node = n_node
            continue
        else:
            break
    else:
        ans += 1 
print(ans)   


# Optimized solution
from itertools import permutations
from copy import deepcopy

N,M = [int(i) for i in input().split()]
links  = set([input().strip() for _ in range(M)])

ans = 0

for path in permutations(list(range(2,N+1))):
    l = deepcopy(links)
    p_node = 1
    for n_node in path:
        e_l = " ".join([str(s) for s in sorted([p_node,n_node])])
        if e_l in l:
            l.remove(e_l)
            p_node = n_node
            continue
        else:
            break
    else:
        ans += 1 

print(ans)
# Original solution
import itertools
n,m=list(map(int,input().split()))
path=[[False]*n for i in range(n)]
for i in range(m):
    a,b=list(map(int,input().split()))
    a-=1
    b-=1
    path[a][b]=True
    path[b][a]=True
ans=0;

for i in itertools.permutations(list(range(n)),n):
    if i[0]==0:
        for j in range(n):
            if j==n-1:
                ans+=1
                break
            if not path[i[j]][i[j+1]]:
                break
print(ans)

# Optimized solution
def dfs(a,count,seen):
    nseen=seen[:]
    ans=0
    nseen[a] = 1;
    if count==n-1:
        return 1
    else:
        for i in g[a]:
            if not seen[i]:
                ans+=dfs(i,count+1,nseen)
        return ans
n,m=list(map(int,input().split()))
g=[[]*n for i in range(n)]
for i in range(m):
    a,b=list(map(int,input().split()))
    a-=1
    b-=1
    g[a].append(b)
    g[b].append(a)
seen=[0]*n
print((dfs(0,0,seen)))
# Original solution
N, M = list(map(int, input().split()))
E = [[] for i in range(M)]
for i in range(M):
  E[i] = [int(x) - 1 for x in input().split()]
cnt = 0
for p in range(1, 2 ** M):
  V = [[] for i in range(N)]
  idx = 0
  while p:
    if p % 2:
      V[E[idx][0]].append(E[idx][1])
      V[E[idx][1]].append(E[idx][0])
    idx += 1
    p //= 2
  if sum([len(v) for v in V]) == 2 * (N - 1) and len(V[0]) == 1:
    P = [0] + V[0]
    while len(V[P[-1]]) == 2:
      P += [V[P[-1]][0] if V[P[-1]][0] != P[-2] else V[P[-1]][1]]
    cnt += 1 if len(P) == N else 0
print(cnt)

# Optimized solution
N, M = list(map(int, input().split()))
G = [[] for i in range(N)]
for i in range(M):
  a, b = list(map(int, input().split()))
  G[a - 1].append(b - 1)
  G[b - 1].append(a - 1)
def dfs(V, v):
  _V = [v for v in V]
  _V[v] = 1
  cnt = 0
  if sum(_V) == N:
    return 1
  else:
    for adj in G[v]:
      if _V[adj] == 0:
        cnt += dfs(_V, adj)
    return cnt
print((dfs([0] * N, 0)))
# Original solution
n,m=list(map(int, input().split()))
alist=[]
for i in range(m):
  a,b=list(map(int, input().split()))
  alist.append([a,b])
  alist.append([b,a])
ans=0
import itertools
t=[i for i in range(1,n+1)]
blist=list(itertools.permutations(t,n))
ans=0
for i in blist:
  flag=True
  for j in range(n-1):
    if [i[j],i[j+1]] not in alist:
      flag=False
    if i[0]!=1:
      flag=False
  if flag:
    ans+=1
print(ans)

# Optimized solution
n,m=list(map(int, input().split()))
alist=[]
for i in range(m):
  a,b=list(map(int, input().split()))
  alist.append([a,b])
  alist.append([b,a])
ans=0
import itertools
t=[i for i in range(1,n+1)]
blist=list(itertools.permutations(t,n))
ans=0
for i in blist:
  flag=True
  for j in range(n-1):
    if [i[j],i[j+1]] not in alist:
      flag=False
  if i[0]!=1:
      flag=False
  if flag:
    ans+=1
print(ans)
# Original solution
import sys
input = sys.stdin.readline
from operator import itemgetter

lis = []
n = 0
m = 0
ans = 0

def dfs(i, d, fr, used):
    global lis, ans
    if i in used:
        return
    if d == n - 1:
        ans += 1
        return
    for j in lis[i]:
        if j != fr:
            used.append(i)
            # print(i+1 , j+1)
            dfs(j, d+1, i, used)
            used.pop()


def main():
    global lis, n, m, ans
    n, m = list(map(int, input().strip().split()))
    lis = [[] for _ in range(8)]
    for _ in range(m):
        a, b = list([x-1 for x in list(map(int, input().strip().split()))])
        lis[a].append(b)
        lis[b].append(a)
    # print("##")
    dfs(0, 0, -1, [])
    print(ans)

if __name__ == '__main__':
    main()


# Optimized solution
import sys
input = sys.stdin.readline
from operator import itemgetter

lis = []
n = 0
m = 0
ans = 0
visited = []

def dfs(i, d, fr):
    global lis, ans, visited
    if visited[i] == 1:
        return
    if d == n - 1:
        ans += 1
        return
    for j in lis[i]:
        if j != fr:
            visited[i] = 1
            # print(i+1 , j+1)
            dfs(j, d+1, i)
            visited[i] = -1


def main():
    global lis, n, m, ans, visited
    n, m = list(map(int, input().strip().split()))
    lis = [[] for _ in range(n)]
    visited = [-1] * n
    for _ in range(m):
        a, b = list([x-1 for x in list(map(int, input().strip().split()))])
        lis[a].append(b)
        lis[b].append(a)
    # print("##")
    dfs(0, 0, -1)
    print(ans)

if __name__ == '__main__':
    main()
# Original solution

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**6)
##############################

# N = 頂点の数(= 数字の数)
# M = 辺の数(= aの行数)

N, M = list(map(int, input().split()))
graph = [ [0 for _ in range(N)] for _ in range(N) ]
visited = [False] * N

for i in range(M):
    a, b = list(map(int, input().split()))
    graph[a-1][b-1] = 1
    graph[b-1][a-1] = 1

#print(graph)

# u は 0-index
def dfs(u):
    visited[u] = True
    if False in visited:
        pass
    else:
        return 1

    count = 0
    for i in range(N):
        if graph[u][i] == False: continue
        if visited[i]: continue

        visited[i] = True
        count += dfs(i)
        visited[i] = False

    return count

count = dfs(0)
print(count)

# Optimized solution

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**6)
##############################

# https://atcoder.jp/contests/abc054/tasks/abc054_c

# N = 頂点の数(= 数字の数)
# M = 辺の数(= aの行数)

N, M = list(map(int, input().split()))
graph = [ [0 for _ in range(N)] for _ in range(N) ]
visited = [False] * N

for i in range(M):
    a, b = list(map(int, input().split()))
    graph[a-1][b-1] = 1
    graph[b-1][a-1] = 1

#print(graph)

# u は 0-index
def dfs(u):
    if False in visited:
        pass
    else:
        return 1

    count = 0
    for i in range(N):
        if graph[u][i] == False: continue
        if visited[i]: continue

        visited[i] = True
        count += dfs(i)
        visited[i] = False

    return count

visited[0] = True
count = dfs(0)
print(count)