CodeEff/ECCO huggingface dataset:
# Original solution
import sys 
sys.setrecursionlimit(1000000)
N, M = list(map(int, input().split()))
ab = [list([int(x)-1 for x in input().split()]) for _ in range(M)]
adlist = [[] for _ in range(N)]
for a, b in ab:
  adlist[a] += [b] 
  adlist[b] += [a] 


used = [0]*N 
global ans 
ans = 0
def dfs(v):
  global ans 
  used[v] = 1 
  if sum(used) == N:
    ans += 1 
    return 

  for u in adlist[v]:
    if used[u] == 0:
      used[u] = 1 
      dfs(u)
      used[u] = 0  

  return 

dfs(0)
print(ans)

# Optimized solution
import sys 
sys.setrecursionlimit(1000000)
n, m = list(map(int, input().split()))
graph = [[] for _ in range(n)]
for _ in range(m):
  a, b = [int(x)-1 for x in input().split()]
  graph[a] += [b]
  graph[b] += [a]

used = [0]*n
global ans 
ans = 0
def dfs(u):
  global ans
  used[u] = 1
  if sum(used) == n:
    ans += 1
    return 
  
  for v in graph[u]:
    if used[v] == 0:
      used[v] = 1
      dfs(v)
      used[v] = 0 

  return 

dfs(0)
print(ans)
# Original solution
n, m = list(map(int, input().split()))
paths = set()

for i in range(m) :
    _a, _b = list(map(int, input().split()))
    paths.add((_a - 1, _b - 1))
    paths.add((_b - 1, _a - 1))

full_mask = "".join(["1" for x in range(n)])
zero_mask = "".join(["0" for x in range(n)])
p_cnt = 0

def dfs(cur_idx, mask) :
    global p_cnt
    
    # set mask and do traverse
    new_mask = list(mask)
    new_mask[cur_idx] = "1"
    new_mask = "".join(new_mask)

    # print("DBG : ", cur_idx, new_mask, full_mask, new_mask == full_mask)
    
    if new_mask == full_mask :
        p_cnt += 1
    else :
        for i in range(n) :
            # if cur_idx -> i in set and i not traversed yet..
            if (cur_idx, i) in paths and mask[i] != "1" :
                dfs(i, new_mask)

dfs(0, zero_mask)
print(p_cnt)
    
            
        

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

zero_mask = "".join(["0" for x in range(n)])
full_mask = "".join(["1" for x in range(n)])

paths_cnt = 0

for i in range(m) :
    _a, _b = list(map(int, input().split()))
    paths.add((_a - 1, _b - 1))
    paths.add((_b - 1, _a - 1))

def mask_idx(s, idx) :
    newmask = s[:idx] + "1" + s[idx + 1:] 
    return newmask 

def dfs(cur_idx, mask) :
    
    global paths_cnt
    new_mask = mask_idx(mask, cur_idx)
    # print("DBG : ", cur_idx, new_mask, full_mask)
    
    if new_mask == full_mask :
        paths_cnt += 1
    for i in range(n) : 
        if i != cur_idx and new_mask[i] != '1' and (cur_idx, i) in paths:
            dfs(i, new_mask)
            
dfs(0, zero_mask)
print(paths_cnt)
# Original solution
N, M = list(map(int, input().split()))
paths = set()

for i in range(M) :
    _f, _t = list(map(int, input().split()))
    paths.add((_f - 1, _t - 1))
    paths.add((_t - 1, _f - 1))

zeromask = "".join(['0' for x in range(N)])
fullmask = "".join(['1' for x in range(N)])
cnt = 0

def do_mask(m, idx) :
    return m[:idx] + '1' + m[idx + 1:]

def dfs(m, idx) :
    global cnt
    new_mask = do_mask(m, idx)
    
    if new_mask == fullmask :
        cnt += 1
    else :
        for i in range(N) :
            if i != idx and m[idx] != '1' and (idx, i) in paths:
                dfs(new_mask, i)
            
dfs(zeromask, 0)
print(cnt)

# Optimized solution
N, M = list(map(int, input().split()))
a, b = [], []

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

zero_mask = "".join(['0' for x in range(N)])
full_mask = "".join(['1' for x in range(N)])
paths_cnt = 0
paths_set = set()

def do_mask(m, idx) :
    newmask = m[:idx] + '1' + m[idx + 1:]
    return newmask

def dfs(m, idx) :
    global paths_cnt
    
    # print("DBG, do dfs with : ", m, idx)
    # do mask for current idx
    newmask = do_mask(m, idx)
    
    if newmask == full_mask :
        paths_cnt += 1
    else :
        for i in range(N) :
            # print("DBG2 : ", idx != i, newmask[i] != '1', (idx, i) in paths_set, (idx, i))
            if idx != i and newmask[i] != '1' and (idx, i) in paths_set:
                dfs(newmask, i)
# generate map
for i in range(M) :
    paths_set.add((a[i], b[i]))
    paths_set.add((b[i], a[i]))
    
dfs(zero_mask, 0)
print(paths_cnt)
# Original solution
def main():
    import sys
    #input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations
    #from itertools import accumulate, product, permutations
    from math import floor, ceil

    #mod = 1000000007

    n,m = list(map(int, input().split()))
    edge = [list(map(int, input().split())) for _ in range(m)]
    res = []
    visited = [0]*n

    def dfs(node):
        visited[node-1]=1
        if sum(visited)==n:
            res.append(1)
            return
        for x,y in edge:
            if x == node:
                if not visited[y-1]:
                    dfs(y)
                    visited[y-1] = 0
            if y == node:
                if not visited[x-1]:
                    dfs(x)
                    visited[x-1] = 0

    for a,b in edge:
        if a==1:
            dfs(a)
            print((len(res)))
            exit()

if __name__ == '__main__':
    main()

# Optimized solution
'''
頂点1から全頂点通る一筆書きが何個あるか
頂点数(N)は最大で8なので道順を全列挙して調べてもいける
'''
def main():
    import sys
    #input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations
    #from itertools import accumulate, product, permutations
    from math import floor, ceil

    #mod = 1000000007


    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)

    res = []
    visited = [0]*N

    def dfs(node):
        visited[node]=1
        if sum(visited)==N:
            res.append(1)
            return
        for n_node in g[node]:
                if not visited[n_node]:
                    dfs(n_node)
                    visited[n_node] = 0
    dfs(0)
    print((len(res)))


    # My
    # n,m = map(int, input().split())
    # edge = [list(map(int, input().split())) for _ in range(m)]
    # res = []
    # visited = [0]*n

    # def dfs(node):
    #     visited[node-1]=1
    #     if sum(visited)==n:
    #         res.append(1)
    #         return
    #     for x,y in edge:
    #         if x == node:
    #             if not visited[y-1]:
    #                 dfs(y)
    #                 visited[y-1] = 0
    #         if y == node:
    #             if not visited[x-1]:
    #                 dfs(x)
    #                 visited[x-1] = 0

    # for a,b in edge:
    #     if a==1:
    #         dfs(a)
    #         print(len(res))
    #         exit()
    #     if b==1:
    #         dfs(b)
    #         print(len(res))
    #         exit()

if __name__ == '__main__':
    main()
# Original solution
'''
頂点1から全頂点通る一筆書きが何個あるか
頂点数(N)は最大で8なので道順を全列挙して調べてもいける
'''
def main():
    import sys
    #input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations
    #from itertools import accumulate, product, permutations
    from math import floor, ceil

    #mod = 1000000007


    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)

    res = []
    visited = [0]*N

    def dfs(node):
        visited[node]=1
        if sum(visited)==N:
            res.append(1)
            return
        for n_node in g[node]:
                if not visited[n_node]:
                    dfs(n_node)
                    visited[n_node] = 0
    dfs(0)
    print((len(res)))


    # My
    # n,m = map(int, input().split())
    # edge = [list(map(int, input().split())) for _ in range(m)]
    # res = []
    # visited = [0]*n

    # def dfs(node):
    #     visited[node-1]=1
    #     if sum(visited)==n:
    #         res.append(1)
    #         return
    #     for x,y in edge:
    #         if x == node:
    #             if not visited[y-1]:
    #                 dfs(y)
    #                 visited[y-1] = 0
    #         if y == node:
    #             if not visited[x-1]:
    #                 dfs(x)
    #                 visited[x-1] = 0

    # for a,b in edge:
    #     if a==1:
    #         dfs(a)
    #         print(len(res))
    #         exit()
    #     if b==1:
    #         dfs(b)
    #         print(len(res))
    #         exit()

if __name__ == '__main__':
    main()

# Optimized solution
res = 0
def main():
    import sys
    #input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations
    #from itertools import accumulate, product, permutations
    from math import floor, ceil

    #mod = 1000000007


    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)

    visited = [0]*N

    def dfs(node):
        global res
        visited[node]=1
        if all(visited):
            res += 1
            return
        for n_node in g[node]:
                if not visited[n_node]:
                    dfs(n_node)
                    visited[n_node] = 0
    dfs(0)
    print(res)

if __name__ == '__main__':
    main()
# Original solution
import sys
input=sys.stdin.readline
#グラフの連結成分を調べる
def Graph(ab):
    G=[[] for i in range(n)]
    for a,b in ab:
        G[a-1].append(b)
        G[b-1].append(a)
    return G
from collections import deque
def dfs(G,v,p,n):
    q=deque()
    q.append((v,p,1,0))
    log=[0]*n
    log[v-1]=1
    ans=0
    while q:
        V,P,cnt,S=q.pop()
        if S==0:
            #下に遷移していくときの処理
            q.append((V,P,cnt,1))
            for new_v in G[V-1]:
                if new_v==P:continue
                if log[new_v-1]:continue
                log[V-1]=1
                q.append((new_v,V,cnt+1,0))
                if cnt==n-1:ans+=1
        else:
            log[P-1]=0
    return ans

n,m=list(map(int,input().split()))
ab=[list(map(int,input().split())) for i in range(m)]
G=Graph(ab)
#print(G)
ans=dfs(G,1,-1,n)
print(ans)

# Optimized solution
import sys
input=sys.stdin.readline
#グラフの連結成分を調べる
def Graph(ab):
    G=[[] for i in range(n)]
    for a,b in ab:
        G[a-1].append(b)
        G[b-1].append(a)
    return G
from collections import deque
def dfs(G,v,p,n):
    q=deque()
    q.append((v,p,1,0))
    log=[0]*n
    log[v-1]=1
    ans=0
    while q:
        V,P,cnt,S=q.pop()
        if S==0:
            #下に遷移していくときの処理
            q.append((V,P,cnt,1))
            for new_v in G[V-1]:
                if new_v==P:continue
                if log[new_v-1]:continue
                log[V-1]=1
                #print(V, new_v, cnt, q, log)
                if cnt==n-1:
                    ans+=1
                    continue
                q.append((new_v,V,cnt+1,0))

        else:
            log[V-1]=0
    return ans

n,m=list(map(int,input().split()))
ab=[list(map(int,input().split())) for i in range(m)]
G=Graph(ab)
#print(G)
ans=dfs(G,1,-1,n)
print(ans)
# Original solution
from itertools import permutations

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

Matrix = [[False for i in range(N)] for j in range(N)]

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

for i in range(N) :
    Matrix[i][i] = True

arange = list(range(2,N+1))

ans = 0
for pm in permutations(arange) :
    pm = [1] + list(pm)
    for row,col in zip(pm,pm[1:]) :
        row -= 1
        col -= 1
        if not Matrix[row][col] :
            break
    else :
        ans += 1
print(ans)


# Optimized solution
from itertools import permutations

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

Matrix = [[False for x in range(N)] for y in range(N)]
for i in range(N) :
    Matrix[i][i] = True
for i in range(M) :
    a,b = list(map(int,input().split()))
    a -= 1
    b -= 1
    Matrix[a][b] = True
    Matrix[b][a] = True

arange = permutations(list(range(1,N)))
ans = 0
for i in arange :
    pm = [0] + list(i)
    for a,b in zip(pm, pm[1:]) :
        if not Matrix[a][b] :
            break
    else :
        ans += 1
print(ans)
# Original solution
from itertools import permutations

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

L = [[] for i in range(N)]

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

P = permutations([0] + [i for i in range(1,N)])

ans = 0

for perm in P :
    visited = [0 for i in range(N)]
    visited[0] = 1
    for i in range(N-1) :
        if perm[i+1] not in L[perm[i]] :
            break
         
        if visited[perm[i+1]] :
            break
        
        visited[perm[i+1]] = 1
    
    if sum(visited) == N :
        ans += 1

print(ans)


# Optimized solution
from itertools import permutations

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

L = [[False for j in range(N)] for i in range(N)]

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

P = list(permutations(list(range(1,N))))

ans = 0

for perm in P :
    perm = list(perm)
    
    for s,g in zip([0] + perm, perm) :
        if not L[s][g] :
            break
    else :
        ans += 1

print(ans)
# Original solution
from itertools import permutations
from math import factorial

n, m = list(map(int, input().split(' ')))
edge = []

for i in range(m):
    ai, bi = list(map(int, input().split(' ')))
    edge.append([ai,bi])


x = [i for i in range(1,n+1)]
ls = list(permutations(x))
ans = 0
for l in range(factorial(n-1)):
    cnt = 0
    for i in range(n-1):
        for j in range(m):
            if (ls[l][i] in edge[j]) and (ls[l][i+1] in edge[j]):
                cnt += 1
    if cnt == n-1:
        ans += 1


print(ans)


# Optimized solution
from itertools import permutations
from math import factorial

n, m = list(map(int, input().split(' ')))
edge = []
for i in range(m):
    ai, bi = list(map(int, input().split(' ')))
    edge.append([ai, bi])

l = [i for i in range(1, n+1)]
ls = list(permutations(l))
ans = 0
for i in range(factorial(n-1)):
    y = 0
    for j in range(n-1):
        for k in edge:
            if (ls[i][j+1] in k) and (ls[i][j] in k):
                y += 1
    if y == n-1:
        ans += 1

print(ans)
# Original solution
import itertools

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

P = N-1
count = 0
for path in itertools.permutations(ab, P):
  flag = True
  prev = 1
  memo = [0]*N
  for i in range(P):
    memo[prev-1] += 1
    if flag == True:
      if path[i][0] == prev:
        prev = path[i][1]
      elif path[i][1] == prev:
        prev = path[i][0]
      else:
        flag = False
        continue
      if 0 < memo[prev-1]:
        flag = False
        continue
      if i == P-1:
        count += 1
        
print(count)


# Optimized solution
import itertools

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

count = 0
for path in itertools.permutations([i for i in range(2, N+1)], N-1):
  flag = True
  if [1, path[0]] in ab or [path[0], 1] in ab:
    pass
  else:
    flag = False
    continue
  for i in range(1, N):
    if flag:
      if i == N-1:
        count += 1
        continue
      if [path[i-1], path[i]] in ab or [path[i], path[i-1]] in ab:
        continue
      else:
        flag = False
print(count)
# Original solution
# https://atcoder.jp/contests/abc054/tasks/abc054_c

import copy
import sys
input = sys.stdin.readline

# 頂点, 辺の数
N, M = list(map(int, input().split()))

# グラフのリスト
# 各頂点からどこの頂点に向かう辺があるかどうかという情報
Graph_list = [[] for i in range(N)]

# 入力
for i in range(M):
    a, b = list(map(int, input().split()))
    a += -1
    b += -1

    # 無向グラフなのでa, b両方
    Graph_list[a].append(b)
    Graph_list[b].append(a)

ans_count = 0           # 正解の経路の数
checked_list = []       # すでに通ったことのあるリスト
throwgh_point_list = [-1 for i in range(N)]     # 経路のリスト（全探索用）

def dfs(i, current, throwgh_point_list):   
    # 頂点をN個通ったら終了処理
    if i >= N-1:
        # 最後の点を追加
        throwgh_point_list[i] = current

        global checked_list
        # すでに考慮したことのあるリストの場合
        if throwgh_point_list in checked_list:
            return

        checked_list.append(copy.copy(throwgh_point_list))

        # 全ての点に到達している場合
        # 順不同で比較
        if set(throwgh_point_list) == set(list(range(N))):
            global ans_count
            ans_count += 1
        return

    for j in Graph_list[current]:
        # 現在地を書き込む
        throwgh_point_list[i] = current

        # 次の点に移動する        
        dfs(i + 1, j, throwgh_point_list)

dfs(0, 0, throwgh_point_list)
print(ans_count)

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

import copy
import sys
input = sys.stdin.readline

# 頂点, 辺の数
N, M = list(map(int, input().split()))

# グラフのリスト
# 各頂点からどこの頂点に向かう辺があるかどうかという情報
Graph_list = [[] for i in range(N)]

# 入力
for i in range(M):
    a, b = list(map(int, input().split()))
    a += -1
    b += -1

    # 無向グラフなのでa, b両方
    Graph_list[a].append(b)
    Graph_list[b].append(a)

ans_count = 0           # 正解の経路の数
visited = [False] * N
visited[0] = True

def dfs(i, current, visited):   
    # 頂点をN個通ったら終了処理
    if i >= N-1:

        # 全ての点に到達している場合
        if all(visited):
            global ans_count
            ans_count += 1
            return 
        return 

    for j in Graph_list[current]:
        if visited[j] == False:
            # 現在地を書き込む
            visited[j] = True
            # 次の点に移動する        
            dfs(i + 1, j, visited)

            visited[j] = False

dfs(0, 0, visited)
print(ans_count)
# Original solution
from itertools import permutations


N, M, *ab = list(map(int, open(0).read().split()))
g = [[0] * N for _ in range(N)]
for a, b in zip(*[iter(ab)] * 2):
    g[a - 1][b - 1] = 1
    g[b - 1][a - 1] = 1

ans = 0
for path in permutations(list(range(1, N))):
    path = [0] + list(path)
    if all(g[v][nv] for v, nv in zip(path, path[1:])):
        ans += 1
print(ans)


# Optimized solution
def dfs(v):
    if sum(visited) == N:
        return 1
    res = 0
    for nv in g[v]:
        if visited[nv]:
            continue
        visited[nv] = 1
        res += dfs(nv)
        visited[nv] = 0
    return res


N, M, *ab = list(map(int, open(0).read().split()))
g = [[] for _ in range(N)]
for a, b in zip(*[iter(ab)] * 2):
    a -= 1
    b -= 1
    g[a].append(b)
    g[b].append(a)

visited = [0] * N
visited[0] = 1
print((dfs(0)))
# Original solution
from copy import deepcopy

cnt = 0
depth = 0


def main():
    n, m = list(map(int, input().split()))
    adj = [[] for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split()))
        a -= 1
        b -= 1
        adj[a].append(b)
        adj[b].append(a)

    def f(u, d):
        global cnt, depth
        cp = deepcopy(d)
        cp[u] = depth
        if cp.count(-1) == 0:
            cnt += 1
        else:
            vs = adj[u]
            depth += 1
            for v in vs:
                if cp[v] == -1:
                    f(v, cp)
            depth -= 1

    f(0, [-1] * n)

    print(cnt)


if __name__ == "__main__":
    main()


# Optimized solution
class Graph:
    def __init__(self, n, adj):
        self.adj = adj
        self.cnt = 0
        self.depth = 0
        self.ds = [-1] * n

    def solve(self, u):
        self.ds[u] = self.depth
        if self.ds.count(-1) == 0:
            self.cnt += 1
            return

        self.depth += 1
        for v in self.adj[u]:
            if self.ds[v] == -1:
                self.solve(v)
                self.ds[v] = -1
        self.depth -= 1


def main():
    n, m = list(map(int, input().split()))
    adj = [[] for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split()))
        a -= 1
        b -= 1
        adj[a].append(b)
        adj[b].append(a)

    graph = Graph(n, adj)
    graph.solve(0)
    print((graph.cnt))


if __name__ == "__main__":
    main()
# Original solution
class Graph:
    def __init__(self):
        n, m = list(map(int, input().split()))

        self.adj = [[] for _ in range(n)]
        for _ in range(m):
            a, b = list(map(int, input().split()))
            a -= 1
            b -= 1
            self.adj[a].append(b)
            self.adj[b].append(a)

        self.cnt = 0
        self.depth = 0
        self.ds = [-1] * n

    def solve(self, u):
        self.ds[u] = self.depth
        if self.ds.count(-1) == 0:
            self.cnt += 1
            return

        self.depth += 1
        for v in self.adj[u]:
            if self.ds[v] == -1:
                self.solve(v)
                self.ds[v] = -1
        self.depth -= 1


def main():
    graph = Graph()
    graph.solve(0)
    print((graph.cnt))


if __name__ == "__main__":
    main()


# Optimized solution
from itertools import permutations

n, m = list(map(int, input().split()))
ab = [list(map(int, input().split())) for _ in range(m)]

g = [[0] * n for _ in range(n)]
for a, b in ab:
    a -= 1
    b -= 1
    g[a][b] = 1
    g[b][a] = 1

ans = 0
for pat in permutations(list(range(1, n)), n - 1):
    is_path = True
    u = 0
    for v in pat:
        if g[u][v] == 0:
            is_path = False
        u = v

    if is_path:
        ans += 1

print(ans)
# Original solution
def DFS(s):
    global ans,color
    color[s]="gray"
    if "white" not in color:
        ans +=1
    for i in M[s]:
        if color[i]=="white":
            DFS(i)
    color[s]="white"


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

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

color=["white" for _ in range(n)]
ans=0
DFS(0)

print(ans)

# Optimized solution
def DFS(s):
    global ans,color
    color[s]="black"
    if "white" not in color:
        ans +=1
    for i in M[s]:
        if color[i]=="white":
            DFS(i)
    color[s]="white"


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

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

color=["white" for _ in range(n)]
ans=0
DFS(0)

print(ans)
# Original solution
def DFS(s):
    global ans,color
    color[s]="black"
    if "white" not in color:
        ans +=1
    for i in M[s]:
        if color[i]=="white":
            DFS(i)
    color[s]="white"


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

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

color=["white" for _ in range(n)]
ans=0
DFS(0)

print(ans)

# Optimized solution
def DFS(num):
    global ans,color
    color[num]="black"
    if "white" not in color:
        ans +=1
    for i in M[num]:
        if color[i]=="white":
            DFS(i)
    color[num]="white"


n,m=list(map(int,input().split()))
AB=[list(map(int,input().split())) for _ in range(m)]

M=[[] for _ in range(n)]
color=["white" for _ in range(n)]
for a,b in AB:
    M[a-1].append(b-1)
    M[b-1].append(a-1)

ans=0
DFS(0)
print(ans)
# Original solution
n, m = list(map(int, input().split()))
g = [[]for _ in range(n + 1)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    g[a].append(b) 
    g[b].append(a)

ret = 0
def walk(node, visited):
    global ret
    tmp = visited + [node]
    if len(tmp) == n:
        ret += 1 
    for nd in g[node]:
        if nd not in tmp:
            walk(nd, tmp)
walk(1, [])
print(ret)


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

ans = 0
def walk(cur, visited):
    global ans
    tmp = visited + [cur]
    if len(tmp) == N:
        ans += 1
    for nex in g[cur]:
        if nex not in tmp:
            walk(nex, tmp)
walk(1, [])
print(ans)