CodeEff/ECCO huggingface dataset:
# Original solution
import copy
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n+1)]
for i in range(m):
    a, b = list(map(int, input().split()))
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
ans = 0

def dfs(node, finished):
    #print("node {}  finished {}".format(node, finished))
    finished.add(node)
    global ans
    if len(finished) == n:
        ans += 1
    else:
        for i in adjacent_list[node]:
            if i not in finished: 
                passed = copy.deepcopy(finished)
                dfs(i, passed)
dfs(1,set([1]))
print(ans)


# Optimized solution
import copy
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n+1)]
for i in range(m):
    a, b = list(map(int, input().split()))
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
ans = 0
def dfs(node,f):
    f.add(node)
    global ans
    if len(f) == n:
        ans += 1
    else:
        for i in adjacent_list[node]:
            if i not in f:
                k = copy.deepcopy(f)
                dfs(i,k)
dfs(1,set())
print(ans)
# Original solution
import copy
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n+1)]
for i in range(m):
    a, b = list(map(int, input().split()))
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
ans = 0
def dfs(node,f):
    f.add(node)
    global ans
    if len(f) == n:
        ans += 1
    else:
        for i in adjacent_list[node]:
            if i not in f:
                k = copy.deepcopy(f)
                dfs(i,k)
dfs(1,set())
print(ans)

# Optimized solution
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n+1)]
for i in range(m):
    a, b = list(map(int, input().split()))
    adjacent_list[a].append(b)
    adjacent_list[b].append(a)
ans = 0
def dfs(node,f):
    global ans
    if len(f) == n:
        ans += 1
    else:
        for i in adjacent_list[node]:
            if i not in f:
                k = f | set([i])
                dfs(i,k)
dfs(1,set([1]))
print(ans)
# Original solution
# -*- coding: utf-8 -*-

import copy

n,m = list(map(int,input().split()))
rinset = [[0]*(n+1) for _ in range(n+1)]
for _ in range(m):
    a,b = list(map(int,input().split()))
    rinset[a][b]=b
    rinset[b][a]=a
cnt = 0
def solve(start,visitted):
    global cnt
    visitted = copy.deepcopy(visitted)
    visitted.append(start)
    if len(visitted) == n:
        cnt+=1
        return
    next_start=[i for i in rinset[start] if (i>1 and i not in visitted)]
    for i in next_start:
        solve(i,visitted)

solve(1,[])
print(cnt)


# Optimized solution
# -*- coding: utf-8 -*-
n,m = list(map(int,input().split()))
ab = [list(map(int,input().split())) for i in range(m)]

#逆順にしたもの追加
ab += [[b,a] for a,b in ab]

#辺id付きで、idがfrom,abi[from]=[to1,to2,...] のリスト
abi = [[] for _ in range(n+1)]
for i,(a,b) in enumerate(ab):
    abi[a].append(b)



#再起のlimitを上げる
import sys
sys.setrecursionlimit(4100000)

def dfs(idx=1,visitted=[1],cnt=1):
    ret = 0
    if cnt==n:
        return 1
    for to in abi[idx]:
        if to not in visitted:
            ret += dfs(to,visitted+[to],cnt+1)
    return ret
print((dfs()))
# Original solution
import itertools

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

count = 0
for V in itertools.permutations(list(range(1, N))):
    if V[0] in E[0] and all(V[i] in E[V[i-1]] for i in range(1, N-1)):
        count += 1
print(count)


# Optimized solution
from itertools import permutations

def int0(s):
    return int(s) - 1

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

    to = [[False]*N for _ in range(N)]
    for a, b in edges:
        to[a][b] = True
        to[b][a] = True
    
    ans = 0
    for p in permutations(list(range(1, N))):
        if to[0][p[0]] and all(to[p[i]][p[i+1]] for i in range(N-2)):
            ans += 1
    print(ans)

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


N, M = list(map(int, input().split()))
edges = [list([int(x) - 1 for x in input().split()]) for _ in range(M)]

res = 0
if M < N - 1:
    print(res)
else:
    for path in itertools.permutations(edges, N - 1):
        vertex = [True] * N
        v = 0
        vertex[v] = False
        for edge in path:
            if v in edge:
                nv = edge[0] if v == edge[1] else edge[1]
                if vertex[nv]:
                    vertex[nv] = False
                    v = nv
                    continue
            break
        else:
            res += 1
    print(res)


# Optimized solution
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)


def dfs(node, track):
    if len(track) == N:
        global res
        res += 1
    else:
        for dst in [x for x in edges[node] if x not in track]:
            dfs(dst, track + tuple([dst]))


res = 0
dfs(0, tuple([0]))
print(res)
# Original solution
import itertools


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

res = 0
if M < N - 1:
    print(res)
else:
    for course in itertools.combinations(edges, N - 1):

        num_of_v = [0] * N
        for edge in course:
            num_of_v[edge[0]] += 1
            num_of_v[edge[1]] += 1
        if num_of_v[0] != 1 and max(num_of_v) != 2:
            continue

        for root in itertools.permutations(course):
            vertex = [False] + [True] * (N - 1)
            v = 0
            for edge in root:
                if v in edge:
                    nv = edge[0] if v == edge[1] else edge[1]
                    if vertex[nv]:
                        vertex[nv] = False
                        v = nv
                        continue
                break
            else:
                res += 1
    print(res)


# Optimized solution
def main():
    import sys
    from itertools import permutations
    # readline = sys.stdin.buffer.readline
    readlines = sys.stdin.readlines
    N, M = list(map(int, input().split()))
    edge = [[0] * N for _ in range(N)]
    for s in readlines():
        a, b = list(map(int, s.split()))
        a -= 1; b -= 1
        edge[a][b] = 1
        edge[b][a] = 1

    cnt = 0
    for path in permutations(list(range(1, N))):
        path = [0] + list(path)
        for i in range(N - 1):
            v = path[i]
            nv = path[i + 1]
            if edge[v][nv] == 0:
                break
        else:
            cnt += 1
    print(cnt)


if __name__ == "__main__":
    main()
# Original solution
import itertools
N,M=list(map(int,input().split()))
edges={tuple(sorted(map(int,input().split()))) for i in range(M)}
ans=0
for i in itertools.permutations(list(range(2,N+1)),N-1):
    l=[1]+list(i)
    ans+=sum(1 for edge in zip(l,l[1:]) if tuple(sorted(edge)) in edges)==N-1
print(ans)

# Optimized solution
import itertools
N,M=list(map(int,input().split()))
edges={tuple(sorted(map(int,input().split()))) for i in range(M)}
ans=0
for i in itertools.permutations(list(range(2,N+1))):
    l=[1]+list(i)
    ans+=sum(1 for edge in zip(l,l[1:]) if tuple(sorted(edge)) in edges)==N-1
print(ans)
# Original solution
import copy
n, m = list(map(int, input().split()))
ab = [list(map(int, input().split())) for _ in range(m)]
cnt = 0
fin = set([i + 1 for i in range(n)])
def path(now, edges, past):
    global cnt
    if set(past) == fin:
        cnt += 1
        return 0
    for i in range(len(edges)):
        if now == edges[i][0] and edges[i][1] not in past:
            new_now = edges[i][1]
            new_edges = copy.deepcopy(edges)
            new_past = copy.deepcopy(past)
            new_edges.pop(i)
            new_past.append(edges[i][1])
            # print("now", now, "edges", edges, "new", new_edges, "past", past, "cnt", cnt)
            path(new_now, new_edges, new_past)
        elif now == edges[i][1] and edges[i][0] not in past:
            new_now = edges[i][0]
            new_edges = copy.deepcopy(edges)
            new_past = copy.deepcopy(past)
            new_edges.pop(i)
            new_past.append(edges[i][0])
            # print("now", now, "edges", edges, "new", new_edges, "past", past, "cnt", cnt)
            path(new_now, new_edges, new_past)

for i in range(m):
    if ab[i][0] == 1:
        edges = copy.deepcopy(ab)
        edges.pop(i)
        path(ab[i][1], edges, [1, ab[i][1]])
    elif ab[i][1] == 1:
        edges = copy.deepcopy(ab)
        edges.pop(i)
        path(ab[i][0], edges, [1, ab[i][0]])
print(cnt)


# Optimized solution
import itertools
n, m = list(map(int, input().split()))
ab = set()

for _ in range(m):
    a, b = list(map(int, input().split()))
    ab.add((a, b))
    ab.add((b, a))

cnt = 0
for x in itertools.permutations(list(range(1, n + 1))):
    if x[0] != 1:
        break
    flag = True
    for i in range(len(x)-1):
        if (x[i], x[i + 1]) not in ab:
            flag = False
            break
    if flag:
        cnt += 1
print(cnt)
# Original solution
N,M = list(map(int,input().split()))
vertex = [[0 for j in range(N+1)] for i in range(N+1)]
AB = [list(map(int,input().split())) for _ in range(M)]

for i in range(M):
    a,b = AB[i]
    vertex[a][b] = 1
    vertex[b][a] = 1

from itertools import permutations

ans = 0
for v in permutations([i+2 for i in range(N-1)], N-1):
    v = [1] + list(v)
    canmake = 1
    for j in range(N-1):
        if not vertex[v[j]][v[j+1]]:
            canmake = 0
            break
    if canmake:
        ans += 1
print(ans)

# Optimized solution
N,M = list(map(int,input().split()))
vertex = [[0 for j in range(N+1)] for i in range(N+1)]

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

from itertools import permutations

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

# Optimized solution
import itertools
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))
  
  
answer=0


for p in itertools.permutations(list(range(1,N+1))):
  if p[0] !=1:
    continue
  bl=True
  for i in range(N-1):
    if(p[i],p[i+1]) not in edges:
      bl =False
      break
  if bl:
    answer +=1
    
    
print(answer)
# Original solution
N, M = list(map(int, input().split()))

v = []

for i in range(M):
    line = list(map(int, input().split()))
    v.append([x - 1 for x in line])

conn = []
for _ in range(N):
    conn.append([False] * N)

visited = [False] * N

for start, end in v:
    conn[start][end] = conn[end][start] = True

def dfs(now, depth):
    if visited[now]:
        return 0
    if depth == N - 1:
        return 1

    visited[now] = True
    ret = 0

    for i in range(N):
        if conn[now][i]:
            ret += dfs(i, depth + 1)
    
    visited[now] = False

    return ret

print((dfs(0,0)))

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

d = [[False for i in range(N)] for i in range(N)]
visited = [False] * N

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

def dfs(now, depth):
    if visited[now]:
        return 0
    if depth == N - 1:
        return 1
    
    ret = 0
    visited[now] = True

    for i in range(N):
        if d[now][i]:
            ret += dfs(i, depth + 1)
    
    visited[now] = False

    return ret

print((dfs(0,0)))
# Original solution
import itertools

def sonzai(path, start, goal):
    for i in path:
        if start in i:
            if start > goal:
                if i[0] == goal:
                    return True
            else:
                if i[1] == goal:
                    return True
    return False

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

# Optimized solution
import itertools

n, m = list(map(int, input().split()))
graph = [[0 for i in range(n)] for j in range(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
ans = 0
for i in itertools.permutations(list(range(2, n + 1))):
    if not graph[0][i[0] - 1]:
        continue
    for j in range(n - 1):
        if j == n - 2:
            ans += 1
            break
        if not graph[i[j] - 1][i[j + 1] - 1]:
            break
print(ans)
# Original solution
import itertools as it

N, M = list(map(int, input().split()))
graph = [[] for i in range(N)]
for i in range(M):
    a, b = list(map(int, input().split()))
    a, b = a - 1, b - 1
    graph[a].append(b)
    graph[b].append(a)
ans = 0
for path in it.permutations(list(range(N))):
    if path[0] != 0:
        continue
    is_connected = True
    for ith_edge in range(len(path) - 1):
        if path[ith_edge + 1] not in graph[path[ith_edge]]:
            is_connected = False
            break
    if is_connected:
        ans += 1
print(ans)


# Optimized solution
import itertools as it

N, M = list(map(int, input().split()))
graph = [[] for i in range(N)]
for i in range(M):
    a, b = list(map(int, input().split()))
    a, b = a - 1, b - 1
    graph[a].append(b)
    graph[b].append(a)
ans = 0
for path in it.permutations(list(range(N))):
    if path[0] != 0:
        break
    is_connected = True
    for ith_edge in range(len(path) - 1):
        if path[ith_edge + 1] not in graph[path[ith_edge]]:
            is_connected = False
            break
    if is_connected:
        ans += 1
print(ans)
# Original solution
from itertools import permutations
def main():
    n, m = list(map(int, input().split()))

    edge = set()
    for _ in range(m):
        a, b = [int(x)-1 for x in input().split()]
        edge.add((a, b))  
        edge.add((b, a))

    #全ノード間に辺が張っていると仮定する
    #このとき全てのノードを廻る順番は順列の数だけある
    #ここから条件を絞って数えるべきものを数えていく 

    #ノードを廻る順を構成する 
    node_num = []
    for i in range(n):
        node_num.append(i)
    
    cnt = 0
    for p in permutations(node_num):
        #数える経路は始点が0である
        if p[0] == 0:
            #この順列pの通りに辿れるように辺が張っているならこの経路は数えるべき経路である
            flag = True
            for i in range(n-1):
                #この順列のあるノード間に辺が存在しないならこの経路は不可能
                if (p[i], p[i+1]) not in edge:
                    flag = False
            if flag:
                cnt += 1 
    print(cnt) 
main()

# Optimized solution
#python3
from itertools import permutations

def main():
    n, m = list(map(int, input().split()))
    edge = set()
    for _ in range(m):
        a, b = list(map(int, input().split()))
        edge.add((a-1, b-1))
        edge.add((b-1, a-1))
    
    node = []
    for i in range(n):
        node.append(i)
    cnt = 0
    for p in permutations(node):
        if p[0] == 0:
            f = True
            for j in range(n-1): 
                if (p[j], p[j+1]) not in edge:
                    f = False
            if f:
                cnt += 1 
    print(cnt)
main()
# Original solution
from itertools import permutations
n, m = list(map(int, input().split()))
edges = [tuple(map(int, input().split())) for _ in range(m)]

ans = 0
for i in permutations(list(range(2, n+1)), n-1):
    load = [1]+list(i)
    ans += sum(1 for edge in zip(load, load[1:])
               if tuple(sorted(edge)) in edges) == n-1
print(ans)


# Optimized solution
from itertools import permutations
n, m = list(map(int, input().split()))
edges = {tuple(map(int, input().split())) for _ in range(m)}

ans = 0
for i in permutations(list(range(2, n+1)), n-1):
    load = [1]+list(i)
    ans += sum(1 for edge in zip(load, load[1:])
               if tuple(sorted(edge)) in edges) == n-1
print(ans)
# Original solution
from sys import stdin


def dfs(e, ans, done, N, graph):
    if (1 << N) - 1 == done:
        ans += 1
        return ans
    for s in graph[e]:
        if done >> s & 1:
            continue
        done ^= 1 << s
        ans = dfs(s, ans, done, N, graph)
        done ^= 1 << s
    return ans


def main():
    lines = stdin.readlines()
    N, M = list(map(int, lines[0].split()))
    graph = [[] for i in range(N)]
    for i in range(1, M + 1):
        a, b = [int(x) - 1 for x in lines[i].split()]
        # 0-based indexing
        graph[a].append(b)
        graph[b].append(a)
    ans = 0
    print((dfs(0, ans, 1, N, graph)))
    return


main()


# Optimized solution
from sys import stdin
N = int()
memo = {}
graph = []


def dfs(e, done):
    if (1 << N) - 1 == done:
        return 1
    key = (e, done)
    if key in memo:
        return memo[key]
    ret = 0
    for s in graph[e]:
        if done >> s & 1:
            continue
        done ^= 1 << s
        ret += dfs(s, done)
        done ^= 1 << s
    memo[key] = ret
    return ret


def main():
    lines = stdin.readlines()
    global N
    N, M = list(map(int, lines[0].split()))
    global graph
    graph = [[] for i in range(N)]
    for i in range(1, M + 1):
        a, b = [int(x) - 1 for x in lines[i].split()]
        # 0-based indexing
        graph[a].append(b)
        graph[b].append(a)
    print((dfs(0, 1)))
    return


main()
# Original solution
n,m=list(map(int,input().split()))
road=[[] for _ in range(n+1)]
for i in range(m):
    a,b=list(map(int,input().split()))
    road[a].append(b)
    road[b].append(a)
dp=[[0]*(n+1) for _ in range(2**n)]
dp[1][1]=1
for i in range(1,2**n):
    for j in range(1,n+1):
        for k in road[j]:
            if not (i>>(k-1))&1:
                dp[i+2**(k-1)][k]+=dp[i][j]
print((sum(dp[2**n-1])))



# Optimized solution
n,m=list(map(int,input().split()))
root=[[] for _ in range(n+1)]
for i in range(m):
    a,b=list(map(int,input().split()))
    root[a].append(b)
    root[b].append(a)
s=[0]*(n+1)
s[0]=1
s[1]=1
ans=0
def f(a,x):
    global ans
    for i in root[a]:
        if x[i]==0:
            x[i]=1
            f(i,x)
            x[i]=0
    if x.count(1)==n+1:
        ans+=1
f(1,s)
print(ans)
# Original solution
n, m = list(map(int, input().split()))
graph = [[] for _ in range(n + 1)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    graph[a].append(b)
    graph[b].append(a)

visit = [0] * (n + 1)


def dfs(now, depth):
    if visit[now]:
        return 0
    if depth == n:
        return 1

    count = 0
    visit[now] = 1
    if graph[now]:
        for i in graph[now]:
            count += dfs(i, depth + 1)
    visit[now] = 0

    return count


ans = dfs(1, 1)
print(ans)


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

visit = [0] * (n + 1)
ans = 0


def dfs(now, depth):
    global ans
    if visit[now]:
        pass
    if depth == n:
        ans += 1

    visit[now] = 1
    if graph[now]:
        for i in graph[now]:
            if visit[i] == 0:
                dfs(i, depth + 1)
    visit[now] = 0


dfs(1, 1)
print(ans)
# Original solution
n,m = list(map(int,input().split()))
graph = [[]for i in range(n)]


for i in range(m):
    a,b = list(map(int,input().split()))
    a -=1
    b-=1
    graph[a].append(b)
    graph[b].append(a)
def all_visited(l):
    a = 0
    for i in range(n):
        if l[i]:
            a+=1
    if a == n:
        return 1
    else: return 0
def dfs(now):

    ans = 0
    visited[now] = 1
  
    if all_visited(visited):
        
        return 1
    for next in graph[now]:
        if visited[next]:continue
        ans += dfs(next)
        visited[next] =0
    return ans
visited = [0]*n
print((dfs(0)))

# Optimized solution
import sys

sys.setrecursionlimit(10**8)
n,m = list(map(int,input().split()))
graph = [[]for i in range(n)]
visited = [0]*n
def all_v(visited):
    cnt = 0
    for x in visited:cnt+=x
    return cnt == n
def dfs(now):
    visited[now] = 1
    if all_v(visited):return 1
    res = 0
    for next in graph[now]:
        if visited[next]:continue
        res += dfs(next)
        visited[next] = 0
    return res
    
for i in range(m):
    a,b = list(map(int,input().split()))
    a-=1
    b -= 1
    graph[a].append(b)
    graph[b].append(a)
print((dfs(0)))
# Original solution
N,M=list(map(int,input().split()))
import copy
a=[0]*M
b=[0]*M
for i in range(M):
    a[i],b[i]=list(map(int,input().split()))
D=[[1]]
def route(D):
    E=[]
    D1=copy.deepcopy(D)
    for j in range(len(D)):
        x=D[j][-1]
        for i in range(M):

            if a[i]==x:
                if not b[i] in D1[j]:
                    D=copy.deepcopy(D1)
                    D[j].append(b[i])
                    E.append(D[j])
            elif b[i]==x:
                if not a[i] in D1[j]:
                    D=copy.deepcopy(D1)
                    D[j].append(a[i])
                    E.append(D[j])
    return E
for i in range(N-1):
    D=copy.deepcopy(route(D))
print((len(D)))

    

# Optimized solution
N,M=list(map(int,input().split()))
import copy
a=[0]*M
b=[0]*M
for i in range(M):
    a[i],b[i]=list(map(int,input().split()))
D=[[1]]
def route(D):
    E=[]
    D1=copy.deepcopy(D)
    for j in range(len(D)):
        x=D[j][-1]
        for i in range(M):

            if a[i]==x:
                if not b[i] in D1[j]:
                    D[j]=copy.deepcopy(D1[j])
                    D[j].append(b[i])
                    E.append(D[j])
            elif b[i]==x:
                if not a[i] in D1[j]:
                    D[j]=copy.deepcopy(D1[j])
                    D[j].append(a[i])
                    E.append(D[j])
    return E
for i in range(N-1):
    D=copy.deepcopy(route(D))
print((len(D)))
# Original solution
N,M=list(map(int,input().split()))
import copy
a=[0]*M
b=[0]*M
for i in range(M):
    a[i],b[i]=list(map(int,input().split()))
D=[[1]]
def route(D):
    E=[]
    D1=copy.deepcopy(D)
    for j in range(len(D)):
        x=D[j][-1]
        for i in range(M):

            if a[i]==x:
                if not b[i] in D1[j]:
                    D[j]=copy.deepcopy(D1[j])
                    D[j].append(b[i])
                    E.append(D[j])
            elif b[i]==x:
                if not a[i] in D1[j]:
                    D[j]=copy.deepcopy(D1[j])
                    D[j].append(a[i])
                    E.append(D[j])
    return E
for i in range(N-1):
    D=copy.deepcopy(route(D))
print((len(D)))

    

# Optimized solution
def bit_DP(N,Adj):
    dp=[[0]*N for i in range(1<<N)]
    dp[1][0]=1
    for S in range(1<<N):
        for v in range(N):
            if (S&(1<<v))==0:
                continue
            sub=S^(1<<v)
            
            for u in range(N):
                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=[[0]*N for i 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()