CodeEff/ECCO huggingface dataset:
# Original solution
# -*- coding: utf-8 -*-

import sys
from itertools import permutations

def input(): return sys.stdin.readline().strip()
def list2d(a, b, c): return [[c] * b for i in range(a)]
def list3d(a, b, c, d): return [[[d] * c for j in range(b)] for i in range(a)]
def list4d(a, b, c, d, e): return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]
def ceil(x, y=1): return int(-(-x // y))
def INT(): return int(eval(input()))
def MAP(): return list(map(int, input().split()))
def LIST(N=None): return list(MAP()) if N is None else [INT() for i in range(N)]
def Yes(): print('Yes')
def No(): print('No')
def YES(): print('YES')
def NO(): print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7

N, M = MAP()
edges = set()
for i in range(M):
    a, b = MAP()
    a -= 1; b -= 1
    edges.add((a, b))
    edges.add((b, a))

cnt = 0
for perm in permutations(list(range(N))):
    if perm[0] != 0:
        continue
    for i in range(N-1):
        a = perm[i]
        b = perm[i+1]
        if (a, b) not in edges:
            break
    else:
        cnt += 1
print(cnt)


# Optimized solution
# -*- coding: utf-8 -*-

import sys

def input(): return sys.stdin.readline().strip()
def list2d(a, b, c): return [[c] * b for i in range(a)]
def list3d(a, b, c, d): return [[[d] * c for j in range(b)] for i in range(a)]
def list4d(a, b, c, d, e): return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]
def ceil(x, y=1): return int(-(-x // y))
def INT(): return int(eval(input()))
def MAP(): return list(map(int, input().split()))
def LIST(N=None): return list(MAP()) if N is None else [INT() for i in range(N)]
def Yes(): print('Yes')
def No(): print('No')
def YES(): print('YES')
def NO(): print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7

N, M = MAP()
G = list2d(N, N, 0)
for i in range(M):
    a, b = MAP()
    a -= 1; b -= 1
    G[a][b] = G[b][a] = 1

# dp[S][i] := 訪問済の頂点集合をSとして、最後に頂点iにいる場合の通り数
dp = list2d(1<<N, N, 0)
# 最初は頂点1にいる状態から
dp[1][0] = 1
for S in range(1, 1<<N):
    for i in range(N):
        # iが遷移元に含まれていない
        if not S & 1<<i:
            continue
        for j in range(N):
            # jが遷移元に含まれている(ので遷移先にはできない)
            if S & 1<<j:
                continue
            # 辺の張られた頂点間であれば遷移させる
            if G[i][j]:
                dp[S|1<<j][j] += dp[S][i]
# 全頂点訪問できた通り数を合計する
ans = sum(dp[(1<<N)-1])
print(ans)
# Original solution
#DFS
from collections import deque

N, M = list(map(int, input().split()))
G = [[] for _ 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)
  
stack = deque([(0, 0)])
visited = [0] * N
depth = 0
ans = 0
while stack:
  now, depth = stack.pop()
  if depth == N-1:
    ans += 1
    continue
  visited[depth] = now
  for nxt in G[now]:
    if nxt not in visited[:depth+1]:
      stack.append((nxt, depth+1))
    
print(ans)

# Optimized solution
#順列全探索

from itertools import permutations

N, M = list(map(int, input().split()))
G = [[0]*N for _ in range(N)]
for i in range(M):
  a, b = list(map(int, input().split()))
  G[a-1][b-1] = 1
  G[b-1][a-1] = 1

perms = permutations(list(range(1, N)))
ans = 0

for perm in perms:
  now = 0
  for v in perm:
    if G[now][v] == 0:
      break
    now = v
  else:
    ans += 1
    
print(ans)
# Original solution
from collections import defaultdict
from itertools import permutations

def main():
    N, M = list(map(int, input().split()))
    g = defaultdict(list)
    for _ in range(M):
        a, b = list(map(int, input().split()))
        g[a].append(b)
        g[b].append(a)

    ans = 0
    for route in permutations(list(range(2, N + 1)), N - 1):
        ok = True
        now = 1
        for r in route:
            if r in g[now]:
                now = r
            else:
                ok = False
        if ok:
            ans += 1

    print(ans)


if __name__ == '__main__':
    main()


# Optimized solution
from collections import defaultdict
from itertools import permutations


def main():
    N, M = list(map(int, input().split()))
    graph = defaultdict(list)
    for _ in range(M):
        a, b = list(map(int, input().split()))
        graph[a].append(b)
        graph[b].append(a)

    ans = 0
    for route in permutations(list(range(2, N + 1)), N - 1):
        ok = True
        now = 1
        for node in route:
            if node in graph[now]:
                now = node
            else:
                ok = False
        ans += ok

    print(ans)


if __name__ == '__main__':
    main()
# Original solution
from collections import defaultdict
from itertools import permutations


def main():
    N, M = list(map(int, input().split()))
    graph = defaultdict(list)
    for _ in range(M):
        a, b = list(map(int, input().split()))
        graph[a].append(b)
        graph[b].append(a)

    ans = 0
    for route in permutations(list(range(2, N + 1)), N - 1):
        ok = True
        now = 1
        for node in route:
            if node in graph[now]:
                now = node
            else:
                ok = False
        ans += ok

    print(ans)


if __name__ == '__main__':
    main()


# Optimized solution
from collections import defaultdict
from itertools import permutations


def main():
    N, M = list(map(int, input().split()))
    s = set()
    for _ in range(M):
        a, b = list(map(int, input().split()))
        s.add((a, b))
        s.add((b, a))
    ans = 0
    for x in permutations(list(range(2, N + 1))):
        now = 1
        for i in range(len(x)):
            if (now, x[i]) not in s:
                break
            now = x[i]
        else:
            ans += 1
    print(ans)

if __name__ == '__main__':
    main()
# Original solution
import itertools
n,m=list(map(int,input().split()))
edge=[[]for i in range(n+1)]

for i in range(m):
    a,b=list(map(int,input().split()))
    edge[a].append(b)
    edge[b].append(a)
    
ans=0
for i in itertools.permutations(list(range(1,n+1))):
    if i[0]!=1:
        continue
    for j in range(n-1):
        if i[j+1] not in edge[i[j]]:
            break
    else:
        ans+=1
print(ans)

# Optimized solution
from itertools import permutations
n,m=list(map(int,input().split()))
graph=[[] for i in range(n+1)]
for i in range(m):
    a,b=list(map(int,input().split()))
    graph[a].append(b)
    graph[b].append(a)

    
ans=0

for i in permutations(list(range(1,n+1))):
    if i[0]!=1:
        continue
    for j in range(n-1):
        if i[j+1] not in graph[i[j]]:
            break
    else:
        ans+=1
print(ans)
# Original solution
import itertools
N, M = list(map(int, input().split()))
edges = {tuple(sorted(map(int, input().split()))) for _ in range(M)}
answer = 0
for pattern in itertools.permutations(list(range(2, N+1)), N-1):
    l = [1] + list(pattern)
    answer += sum(1 for edge in zip(l, l[1:]) if tuple(sorted(edge)) in edges)==N-1
print(answer)    

# Optimized solution
import itertools

N, M = list(map(int, input().split()))
edges = {tuple(sorted(map(int, input().split()))) for _ in range(M)}

answer = 0
for i in itertools.permutations(list(range(2, N+1)), N-1):
    l = [1] + list(i)
    answer += sum(1 for edge in zip(l, l[1:]) if tuple(sorted(edge)) in edges) == N-1
print(answer)
# Original solution
import itertools

N, M = list(map(int, input().split()))
edges = [tuple(sorted(map(int, input().split()))) for _ in range(M)]

answer = 0
for i in itertools.permutations(list(range(2, N+1)), N-1):
    l = [1] + list(i)
    answer += sum(1 for x in zip(l, l[1:]) if tuple(sorted(x)) in edges) == N-1
print(answer)    

# Optimized solution
from itertools import permutations

N, M = list(map(int, input().split()))
AB = set([tuple(sorted(map(int, input().split()))) for _ in range(M)])

answer = 0
for pattern in permutations(list(range(2, N+1)), N-1):
    pattern = [1] + list(pattern)
    for i in zip(pattern[:-1], pattern[1:]):
        if tuple(sorted(i)) not in AB:
            break
    else:
        answer += 1
print(answer)
# Original solution
import itertools

n, m = list(map(int, input().split()))
h = [[0]*n for _ in range(n)]
for i in range(m):
    a, b = list(map(int, input().split()))
    h[a-1][b-1] = 1
    h[b-1][a-1] = 1

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

# Optimized solution
import itertools

n, m = list(map(int, input().split()))
g = [[0]*n for _ in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    a, b = a-1, b-1
    g[a][b] = 1
    g[b][a] = 1

a = list(itertools.permutations(list(range(n))))
ans = 0
for i in a:
    if i[0] != 0:
        break
    for j in range(n-1):
        if g[i[j]][i[j+1]] == 0:
            break
    else:
        ans += 1
print(ans)
# Original solution
import sys
from itertools import permutations

def solve():
    input = sys.stdin.readline
    N, M = list(map(int, input().split()))
    Edge = [[] for _ in range(N)]
    for _ in range(M):
        a, b = list(map(int, input().split()))
        Edge[a-1].append(b-1)
        Edge[b-1].append(a-1)

    count = 0
    for s in permutations(list(range(N)), N):
        Visited = [False for _ in range(N)]
        for i, n in enumerate(s):
            if i == 0:
                if n != 0: break
                else: Visited[0] = True
            else:
                if n in Edge[s[i-1]]: Visited[n] = True
                else: break
        else: count += 1
    print(count)

    return 0

if __name__ == "__main__":
    solve()

# Optimized solution
import sys
from itertools import permutations

def solve():
    N, M = list(map(int, input().split()))
    Edge = [[] for _ in range(N)]
    for _ in range(M):
        a, b = list(map(int, input().split()))
        Edge[a-1].append(b-1)
        Edge[b-1].append(a-1)
    count = 0
    for order in permutations(list(range(N))):
        if order[0] != 0: continue
        for i in range(N-1):
            if order[i+1] not in Edge[order[i]]: break
        else: count += 1
    print(count)

    return 0

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

line = input().split(" ")
n = int(line[0])
m = int(line[1])
edge = [[] for _ in range(n+1)]

for _ in range(m):
    line = input().split(" ")
    a = int(line[0])
    b = int(line[1])

    edge[a].append(b)
    edge[b].append(a)


visited = [False for _ in range(n+1)]
visited[0] = True#dummy
visited[1] = True

def solve(x):
    allVisited = True
    for e in visited:
        allVisited = allVisited and e
    if allVisited:
        return 1

    ret = 0
    for e in edge[x]:
        if not visited[e]:
            visited[e] = True
            ret += solve(e)
            visited[e] = False
    return ret


print((solve(1)))


# Optimized solution
# -*- coding: utf-8 -*-
n,m = list(map(int, input().split()))
edge = [[] for _ in range(n+1)]
for _ in range(m):
    a,b = list(map(int, input().split()))
    a -= 1
    b -= 1
    edge[a].append(b)
    edge[b].append(a)

visited = [False for _ in range(n)]
def dfs(v):
    if all(visited):
        return 1
    res = 0
    for e in edge[v]:
        if not visited[e]:
            visited[e] = True
            res += dfs(e)
            visited[e] = False
    return res

visited[0] = True
print((dfs(0)))
# Original solution
n,m=list(map(int,input().split()))
e=[[]for _ in[0]*-~n]
for _ in[0]*m:
    a,b=list(map(int,input().split()))
    e[a]+=[b]
    e[b]+=[a]
candy=[[1]]
for _ in[0]*~-n:
    tmp=[]
    for c in candy:
        for next in e[c[-1]]:
            tmp+=[c+[next]]
    candy=tmp
print((sum(c==set(range(1,n+1))for c in map(set,candy))))

# Optimized solution
from itertools import permutations

N, M = list(map(int, input().split()))
edges = set()
for _ in range(M):
    a, b = list(map(int, input().split()))
    edges.add((a, b))
    edges.add((b, a))

cnt = 0
for p in permutations(list(range(2, N + 1))):
    cnt += all(move in edges for move in zip((1,) + p, p))
print(cnt)
# Original solution
# 入力
import sys
stdin = sys.stdin

def li(): return [int(x) for x in stdin.readline().split()]
def li_(): return [int(x)-1 for x in stdin.readline().split()]
def lf(): return [float(x) for x in stdin.readline().split()]
def ls(): return stdin.readline().split()
def ns(): return stdin.readline().rstrip()
def lc(): return list(ns())
def ni(): return int(ns())
def nf(): return float(ns())

from itertools import permutations

# 全探索をするのです
n,m = li()
edges = set()
for _ in range(m):
    a,b = li()
    edges.add((a,b))
    edges.add((b,a))
    
paths = permutations([str(i) for i in range(2,n+1)],n-1)
cnt = 0
for path in paths:
    path = [1] + [int(i) for i in path]
    
    exist = True
    for i in range(n-1):
        if not (path[i], path[i+1]) in edges:
            exist = False

    if exist:
        cnt += 1
        
print(cnt)

# Optimized solution
import sys
stdin = sys.stdin
 
sys.setrecursionlimit(10**5) 
 
def li(): return list(map(int, stdin.readline().split()))
def li_(): return [int(x)-1 for x in stdin.readline().split()]
def lf(): return list(map(float, stdin.readline().split()))
def ls(): return stdin.readline().split()
def ns(): return stdin.readline().rstrip()
def lc(): return list(ns())
def ni(): return int(stdin.readline())
def nf(): return float(stdin.readline())

from itertools import permutations

n,m = li()
graph = [[False]*n for _ in range(n)]

for _ in range(m):
    a,b = li_()
    graph[a][b] = True
    graph[b][a] = True
    
cands = list(permutations([i for i in range(1,n)]))

ans = 0

for c in cands:
    cand = [0] + list(c)
    ok = True
    for i in range(n-1):
        if not graph[cand[i+1]][cand[i]]:
            ok = False
    
    if ok:   
        ans += 1
    
print(ans)
# Original solution
N,M = list(map(int,input().split()))
G = {}
for _ in range(M):
    a,b = list(map(int,input().split()))
    if a not in G:
        G[a] = []
    G[a].append(b)
    if b not in G:
        G[b] = []
    G[b].append(a)
hist = [0 for _ in range(N+1)]
stack = [1]
hist[1] = 1
cnt = 0
F = {}
while stack:
    cur = stack[-1]
    if cur not in F:
        F[cur] = G[cur][:]
        F[cur] = iter(F[cur])
    F1 = list(F[cur])
#     print("cur={},F1={}".format(cur,F1))
    if len(F1)>0:
        F[cur] = iter(F1)
        x = next(F[cur])
        if hist[x]==0:
            stack.append(x)
            hist[x] = 1
        else:
            if sum(hist)==N:
                cnt += 1
                hist[cur]=0
                del F[cur]
                stack.pop()
    else:
#         print("cur={}".format(cur))
#         print("stack={}".format(stack))
        if sum(hist)==N:
            cnt += 1
        hist[cur]=0
        del F[cur]
        stack.pop()
print(cnt)

# Optimized solution
from itertools import permutations
def check(i,j):
    if j==N-2 and x[j] in G[i]:
        return True
    if x[j] in G[i]:
        return check(x[j],j+1)
    return False
    
N,M = list(map(int,input().split()))
G = {i:[] for i in range(1,N+1)}
for _ in range(M):
    a,b = list(map(int,input().split()))
    G[a].append(b)
    G[b].append(a)
cnt = 0
for x in permutations(list(range(2,N+1)),N-1):
    if check(1,0):
        cnt += 1
print(cnt)
# Original solution
import math
from math import gcd,pi,sqrt
INF = float("inf")
MOD = 10**9 + 7

import sys
sys.setrecursionlimit(10**6)
import itertools
import bisect
from collections import Counter,deque
def i_input(): return int(eval(input()))
def i_map(): return list(map(int, input().split()))
def i_list(): return list(i_map())
def i_row(N): return [i_input() for _ in range(N)]
def i_row_list(N): return [i_list() for _ in range(N)]
def s_input(): return eval(input())
def s_map(): return input().split()
def s_list(): return list(s_map())
def s_row(N): return [s_input for _ in range(N)]
def s_row_str(N): return [s_list() for _ in range(N)]
def s_row_list(N): return [list(s_input()) for _ in range(N)]


def main():
    N,m = i_map()
    l = [[0]*N for i in range(N)]

    for i in range(m):
        a,b = i_map()
        a -= 1
        b -= 1
        l[a][b] = 1
        l[b][a] = 1

    L = []

    def dfs(n,a):
        a = a + str(n)
        if len(a) == N:
            L.append(1)
            return

        for i in range(N):
            if l[n][i] == 1 and str(i) not in a:
                dfs(i,a)

    dfs(0,"")
    print((len(L)))





if __name__=="__main__":
    main()


# Optimized solution
import math
from math import gcd,pi,sqrt
INF = float("inf")
MOD = 10**9 + 7

import sys
sys.setrecursionlimit(10**6)
import itertools
import bisect
from collections import Counter,deque
def i_input(): return int(eval(input()))
def i_map(): return list(map(int, input().split()))
def i_list(): return list(i_map())
def i_row(N): return [i_input() for _ in range(N)]
def i_row_list(N): return [i_list() for _ in range(N)]
def s_input(): return eval(input())
def s_map(): return input().split()
def s_list(): return list(s_map())
def s_row(N): return [s_input for _ in range(N)]
def s_row_str(N): return [s_list() for _ in range(N)]
def s_row_list(N): return [list(s_input()) for _ in range(N)]


def main():
    global L
    N,m = i_map()
    l = [[0]*N for i in range(N)]

    for i in range(m):
        a,b = i_map()
        a -= 1
        b -= 1
        l[a][b] = 1
        l[b][a] = 1

    L = 0
    v = [0] * N
    v[0] = 1

    def dfs(n):
        global L
        if 0 not in v:
            L += 1
            return

        for i in range(N):
            if l[n][i] == 1 and v[i] == 0:
                v[i] = 1
                dfs(i)
                v[i] = 0

    dfs(0)
    print(L)



if __name__=="__main__":
    main()
# Original solution
from collections import defaultdict
import itertools

n, m = list(map(int, input().split()))
connected_dict = defaultdict(lambda: [])

for i in range(m):
    a, b = list(map(int, input().split()))
    connected_dict[a].append(b)
    connected_dict[b].append(a)

count = 0
for permutation in list(itertools.permutations(list(range(2, n + 1)))):
    flag = True
    pre_num = 1
    for num in permutation:
        if num not in connected_dict[pre_num]:
            flag = False
            break
        pre_num = num
    if flag:
        count += 1
print(count)


# Optimized solution
# One-stroke Path
import itertools
n, m = list(map(int, input().split()))
ab = {}
for i in range(n+1):
    ab[i] = []
for i in range(m):
    a, b = list(map(int, input().split()))
    ab[a].append(b)
    ab[b].append(a)

count = 0

for values in list(itertools.permutations(list(range(2, n+1)))):
    pre = 1
    for i, v in enumerate(values):
        if(v not in ab[pre]):
            break
        if i == n-2:
            count += 1
        pre = v
print(count)
# Original solution
import itertools
N,M=list(map(int,input().split()))
ab=list(list(map(int,input().split())) for _ in range(M))
l=list(l for l in range(1,N+1))
numlist=list(itertools.permutations(l))
ans=0
for I in numlist:
    if I[0]==1 and all(sorted([I[j],I[j+1]]) in ab for j in range(N-1)):
        ans+=1
print(ans)


# Optimized 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)
# Original solution
from copy import deepcopy


def solve(road, num, ans, n):
    pattern = 0
    test = deepcopy(road)
    if ans.count(str(num)) > 1:
        return 0
    if len(ans) is n:
        return 1
    if len(road[num - 1]) == int(0):
        return 0
    else:
        for i in range(len(road[num - 1])):
            tmp = test[num - 1][-1]
            if tmp is not 0:
                word = ans + str(tmp)
            test[num - 1].pop()
            pattern += solve(test, tmp, word, n)
    return pattern


N, M = [int(i) for i in input().split()]
town = []
for i in range(N):
    town.append(deepcopy([]))

for i in range(M):
    a, b = [int(i) for i in input().split()]
    town[a - 1].append(b)
    town[b - 1].append(a)
print((solve(town, 1, '1', N)))


# Optimized solution
from copy import deepcopy


def solve(road, num, ans, n):
    pattern = 0
    test = deepcopy(road)
    for s in test:
        if num in s:
            s.remove(num)
    if len(ans) is n:
        return 1
    if len(test[num - 1]) == int(0):
        return 0
    else:
        for i in range(len(test[num - 1])):
            tmp = test[num - 1][i]
            if tmp is not 0:
                word = ans + str(tmp)
            pattern += solve(test, tmp, word, n)
    return pattern


N, M = [int(i) for i in input().split()]
town = []
for i in range(N):
    town.append(deepcopy([]))

for i in range(M):
    a, b = [int(i) for i in input().split()]
    if a is not 1 or b is not 1:
        town[a - 1].append(b)
        town[b - 1].append(a)
print((solve(town, 1, '1', N)))
# Original solution
from copy import deepcopy


def solve(road, num, ans, n):
    pattern = 0
    test = deepcopy(road)
    for s in test:
        if num in s:
            s.remove(num)
    if len(ans) is n:
        return 1
    if len(test[num - 1]) == int(0):
        return 0
    else:
        for i in range(len(test[num - 1])):
            tmp = test[num - 1][i]
            if tmp is not 0:
                word = ans + str(tmp)
            pattern += solve(test, tmp, word, n)
    return pattern


N, M = [int(i) for i in input().split()]
town = []
for i in range(N):
    town.append(deepcopy([]))

for i in range(M):
    a, b = [int(i) for i in input().split()]
    if a is not 1 or b is not 1:
        town[a - 1].append(b)
        town[b - 1].append(a)
print((solve(town, 1, '1', N)))


# Optimized solution
N, M = [int(i) for i in input().split()]
road = [list() for i in range(N + 1)]
for i in range(M):
    a, b = [int(i) for i in input().split()]
    road[a].append(b)
    road[b].append(a)


def solve(before, visited, now):
    visited.append(now)
    if len(visited) is N:
        return 1
    pattern = 0
    for way in road[now]:
        if way is now:
            continue
        if way in visited:
            continue
        pattern += solve(now, visited[:], way)
    return pattern


print((solve(0, [], 1)))
# Original solution
N,M=list(map(int,input().split()))
edges=[[] for _ in range(N)]
for i in range(M):
  a,b=list(map(int,input().split()))
  edges[a-1]+=[b-1]
  edges[b-1]+=[a-1]
vis=[1]+[0]*(N-1)#訪問フラグ

ans=0
def DFS(v):
  global ans
  if vis==[1]*N: 
    ans+=1
    return 0
  for u in edges[v]:
    if vis[u]==0:
      vis[u]=1
      DFS(u)
      vis[u]=0
  else: return 0
DFS(0)
print(ans)

# Optimized solution
N,M=list(map(int,input().split()))
edges=[[] for _ in range(N)]
for i in range(M):
  a,b=list(map(int,input().split()))
  edges[a-1]+=[b-1]
  edges[b-1]+=[a-1]
vis=[1]+[0]*(N-1)#訪問フラグ

def DFS(v):
  if vis==[1]*N: 
    return 1
  ret=0
  for u in edges[v]:
    if vis[u]==0:
      vis[u]=1
      ret+=DFS(u)
      vis[u]=0
  else: return ret
print((DFS(0)))
# 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:
        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()))
matrix=[[0]*N for i in range(N)]
for i in range(M):
    a, b = list(map(int, input().split()))
    matrix[a-1][b-1]=1
    matrix[b-1][a-1]=1
import itertools 
count=0
for i in itertools.permutations(list(range(N))):
    if i[0]==0:
        result=1
        for j in range(N-1):
            result*=matrix[i[j]][i[j+1]]
        if result==1:
            count+=1
    else:
        break
print(count)