You are given an undirected connected graph with N vertices and M edges that does not contain self-loops and double edges.

The i-th edge (1 \leq i \leq M) connects Vertex a_i and Vertex b_i.  
An edge whose removal disconnects the graph is called a bridge.

Find the number of the edges that are bridges among the M edges.  

-----Notes-----
 - A self-loop is an edge i such that a_i=b_i (1 \leq i \leq M).
 - Double edges are a pair of edges i,j such that a_i=a_j and b_i=b_j (1 \leq i<j \leq M).
 - An undirected graph is said to be connected when there exists a path between every pair of vertices.

-----Constraints-----
 - 2 \leq N \leq 50
 - N-1 \leq M \leq min(N(N−1)⁄2,50)
 - 1 \leq a_i<b_i \leq N
 - The given graph does not contain self-loops and double edges.
 - The given graph is connected.

-----Input-----
Input is given from Standard Input in the following format:  
N M  
a_1 b_1  
a_2 b_2
:  
a_M b_M

-----Output-----
Print the number of the edges that are bridges among the M edges.

-----Sample Input-----
7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7

-----Sample Output-----
4

The figure below shows the given graph:
The edges shown in red are bridges. There are four of them.

Difficulty: introductory

Starter code:

Solutions:
import sys
sys.setrecursionlimit(10 ** 7)
def input() : return sys.stdin.readline().strip()
def INT()   : return int(input())
def MAP()   : return map(int,input().split())
def LIST()  : return list(MAP())
def NIJIGEN(H): return [list(input()) for i in range(H)]
def dfs(j):
  if j not in finish:
    finish.add(j)
    for k in L[j]:
      dfs(k)
N,M=MAP()
s=list()
L=[[] for _ in range(N)]
for i in range(M):
  a,b=MAP()
  a-=1
  b-=1
  L[a].append(b)
  L[b].append(a)
  s.append([a,b])
ans=0
for i in range(M):
  a,b=s[i]
  L[a].remove(b)
  L[b].remove(a)
  finish=set()
  dfs(a)
  if len(finish)!=N:
    ans+=1
  L[a].append(b)
  L[b].append(a)
print(ans)

class UnionFind():
    """
    parents
        各要素の親要素の番号を格納するリスト
        要素が根（ルート）の場合は-(そのグループの要素数)を格納する
    find(x)
        要素xが属するグループの根を返す
    union(x, y)
        要素xが属するグループと要素yが属するグループとを併合する
    size(x)
        要素xが属するグループのサイズ（要素数）を返す
    same(x, y)
        要素x, yが同じグループに属するかどうかを返す
    members(x)
        要素xが属するグループに属する要素をリストで返す
        関連記事: Pythonリスト内包表記の使い方
    roots()
        すべての根の要素をリストで返す
    group_count()
        グループの数を返す
    all_group_members
        {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す
        関連記事: Pythonで辞書を作成するdict()と波括弧、辞書内包表記
    __str__()
        print()での表示用
        ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す
    """
    
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


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

for i in range(M):
    uf = UnionFind(N)
    
    for j in range(M):
        if i!=j:
            a,b=ab[j][0],ab[j][1]
            uf.union(a-1,b-1)
    #print(i)
    if uf.group_count()!=1:
        ans+=1
        
print(ans)



from collections import deque
def BFS(N,M,List):
    Edge = [[] for TN in range(N+1)]
    for TM in range(0,M):
        Edge[List[TM][0]].append(List[TM][1])
        Edge[List[TM][1]].append(List[TM][0])

    Distance = [-1]*(N+1)
    Distance[0] = 0
    Distance[1] = 0
    
    From = [0]*(N+1)
    From[1] = 1

    Deque = deque()
    Deque.append(1)
    while Deque:
        Now = Deque.popleft()
        for Con in Edge[Now]:
            if Distance[Con]==-1:
                Distance[Con] = Distance[Now]+1
                Deque.append(Con)
                From[Con] = Now

    return Distance[1:],From[1:]

import copy
N,M = (int(T) for T in input().split())
List = [[] for TM in range(0,M)]
for TM in range(0,M):
    List[TM] = [int(T) for T in input().split()]
Count = 0
for TM in range(0,M):
    ListCopy = copy.deepcopy(List)
    del ListCopy[TM]
    Distance,From = BFS(N,M-1,ListCopy)
    if -1 in Distance:
        Count += 1
print(Count)

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

def find(x):
    if root[x] < 0:
        return x
    else:
        root[x] = find(root[x])
        return root[x]

def unit(x, y):
    gx = find(x)
    gy = find(y)

    if gx == gy:
        return

    if root[gx] > root[gy]:
        gx, gy = gy, gx

    root[gx] += root[gy]
    root[gy] = gx

cnt = 0
for i in range(m):
    root = [-1] * n
    for j in range(m):
        if i == j:continue
        unit(AB[j][0]-1, AB[j][1]-1)
    roots = [i for i in root if i < 0]
    cnt += (len(roots) != 1)
print(cnt)

from collections import deque
from sys import stdin
input = stdin.readline

N,M = map(int, input().split())
neighbor = [[] for _ in range(N)]
A = [-1]*M; B = [-1]*M
for i in range(M):
    a,b = map(lambda x: int(x) - 1, input().split())
    A[i] = a; B[i] = b
    neighbor[a].append(b)
    neighbor[b].append(a)

cnt = 0
for i in range(M):
    a,b = A[i],B[i]
    neighbor[a].remove(b)
    neighbor[b].remove(a)
    visited = [False]*N
    queue = deque()
    queue.append(0)
    visited[0] = True
    
    while queue:
        x = queue.popleft()
        
        for z in neighbor[x]:
            if not visited[z]:
                visited[z] = True
                queue.append(z)
    
    
    if False in visited:
        cnt += 1
    
    neighbor[a].append(b)
    neighbor[b].append(a)

print(cnt)

class DisjointSet:
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return -self.parents[self.find(x)]


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

ans = 0
for i in range(M):
    ds = DisjointSet(N)
    for j in range(M):
        if i == j:
            continue
        ds.union(*edges[j])
    if len([-p for p in ds.parents if p < 0]) > 1:
        ans += 1
print(ans)


N,M = map(int,input().split())
G = [[] for _ in range(N)]
H = []
for i in range(M):
  a,b = map(int,input().split())
  a-=1;b-=1 #0index
  G[a].append([b,i]);G[b].append([a,i]) #iを辺のIDとして保存
  H.append([a,b])
ans = 0
 
def dfs(v,ID): #IDの辺を使えない
  visited.add(v)
  for u,idx in G[v]:
    if idx == ID or u in visited:
      continue
    dfs(u,ID)
 
for i in range(M):
  visited = set([])
  start = H[i][0]
  goal = H[i][1]
  dfs(start,i)
  if goal not in visited:
    ans +=1
print(ans)

class UnionFindWithSize:
    def __init__(self, size):
        self.parent = [i for i in range(size)]
        self.size = [1]*size
    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return
        if self.size[x] < self.size[y]:
            self.size[y] += self.size[x]
            self.parent[x] = y
        else:
            self.size[x] += self.size[y]
            self.parent[y] = x
    def same(self, x, y):
        return self.find(x) == self.find(y)
    def sizeofset(self, x):
        return self.size[self.find(x)]
def __starting_point():
    N,M = map(int,input().split())
    edges = [tuple(map(lambda x:int(x)-1,input().split())) for _ in range(M)]
    ans = 0
    for i in range(M):
        uf = UnionFindWithSize(N)
        for j in range(M):
            if j != i:
                a,b = edges[j]
                uf.unite(a,b)
        if uf.sizeofset(0) != N:
            ans += 1
    print(ans)
__starting_point()

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.para = [-1] * (n + 1)
    
    def find(self, x):
        if self.para[x] < 0:
            return x
        else:
            self.para[x] = self.find(self.para[x])
            return self.para[x]
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x > y:
            x, y = y, x
        if x == y:
            return
        else:
            self.para[x] += self.para[y]
            self.para[y] = x
    def isSame(self, x, y):
        return self.find(x) == self.find(y)
    
    def count(self,x):
        return -self.para[self.find(x)]
N, M = map(int, input().split())
un_orginal = UnionFind(N)
A = [tuple(map(int, input().split())) for _ in range(M)]
for a,b in A:
    un_orginal.unite(a,b)
ans = 0
for i in range(M):
    un = UnionFind(N)
    for k in range(M):
        if i == k:
            continue
        else:
            un.unite(A[k][0], A[k][1])
    cnt = 0
    for k in range(N+1):
        if un_orginal.count(k) == un.count(k):
            cnt += 1
    if cnt == N+1:
        ans += 1
print(M-ans)

from networkx import *
n, m = map(int, input().split())
a = [list(map(int, input().split())) for _ in range(m)]
g = Graph(a)
ans = 0
for x in a:
  g.remove_edges_from([x])
  if not is_connected(g):
    ans += 1
  g.add_edges_from([x])
print(ans)

N,M = map(int,input().split())
AB = [tuple(map(int,input().split())) for i in range(M)]

class UnionFind:
    def __init__(self,N):
        self.parent = [i for i in range(N)]
        self._size = [1] * N
        self.count = 0
    def root(self,a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.root(self.parent[a])
            return self.parent[a]
    def is_same(self,a,b):
        return self.root(a) == self.root(b)
    def unite(self,a,b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb: return
        if self._size[ra] < self._size[rb]: ra,rb = rb,ra
        self._size[ra] += self._size[rb]
        self.parent[rb] = ra
        self.count += 1
    def size(self,a):
        return self._size[self.root(a)]

ans = 0
for i in range(M):
    uf = UnionFind(N)
    for j,(a,b) in enumerate(AB):
        if i==j: continue
        a,b = a-1,b-1
        if uf.is_same(a,b): continue
        uf.unite(a,b)
    if uf.size(0) != N:
        ans += 1
print(ans)

3
# coding: utf-8
from collections import defaultdict

class UnionFind(object):
    def __init__(self, N):
        self.parent = [x for x in range(N)] 

    def root(self, x):
        if self.parent[x] == x: return x
        return self.root(self.parent[x]) 

    def unite(self, x, y):
        root_x = self.root(x)
        root_y = self.root(y)
        if root_x != root_y:
            self.parent[root_x] = root_y
    
    def same(self, x, y):
        root_x = self.root(x)
        root_y = self.root(y)
        return root_x == root_y
    
    def num_group(self):
        return sum(1 for i in range(len(self.parent)) if self.parent[i] == i)

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

def isBridge(nth):
    union_find = UnionFind(N)
    for i in range(M): 
        if i == nth: continue
        union_find.unite(B[i][0], B[i][1])
    if union_find.num_group() != 1:
        return 1

ret = 0
for i in range(M):
    if isBridge(i):
        ret += 1
print(ret)



N,M=map(int,input().split())
AB=[list(map(int,input().split())) for i in range(M)]
r=0
for m in range(M):
    c=[[] for i in range(N)]
    for i,(a,b) in enumerate(AB):
        if i!=m:
            c[a-1].append(b-1)
            c[b-1].append(a-1)
    q=[0]
    v=[1]+[0]*(N-1)
    while q:
        p=q.pop()
        for n in c[p]:
            if v[n]==0:
                v[n]=1
                q.append(n)
    if 0 in v:
        r+=1
print(r)

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
 
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
 
    def unite(self, x, y):# UF.unite(a-1,b-1)
        x = self.find(x)
        y = self.find(y)
 
        if x == y:
            return
 
        if self.parents[x] > self.parents[y]:
            x, y = y, x
 
        self.parents[x] += self.parents[y]
        self.parents[y] = x
 
    def size(self, x):#今回は使っていない
        return -self.parents[self.find(x)]
 
    def same(self, x, y):#UF.same(a-1,b-1) True/False
        return self.find(x) == self.find(y)

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

A=[0]*M;t=0;B=[0]*M

for i in range(M):
  a,b=map(int,input().split())
  A[i]=[a-1,b-1]
for t in range(M):
  UF=UnionFind(N)
  for i in range(M):
    if i!=t:
      UF.unite(A[i][0],A[i][1])
  if UF.same(A[t][0],A[t][1])==False:
    B[t]=1
print(sum(B))

class UnionFind():
    def __init__(self, n):
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

n,m = map(int,input().split())
a = [list(map(int,input().split())) for i in range(m)]
ans = 0
for i in range(m):
    uf = UnionFind(n+1)
    cnt = 0
    for j in range(m):
        if i == j:
            continue
        else:
            uf.union(a[j][0],a[j][1])
    for k in uf.parents:
        if k < 0:
            cnt += 1
    if cnt != 2:
        ans += 1

print(ans)

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


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

cnt = 0
for i in range(M):
  uf = UnionFind(N+1)
  for a, b in [*ABS[:i], *ABS[i+1:]]:
    uf.union(a, b)
  if uf.group_count() > 2:
    cnt += 1

print(cnt)


class UnionFind:
  def __init__(self,n):
    self.nodes=n
    self.parents=[i for i in range(n)]
    self.sizes=[1]*n
    self.rank=[0]*n

  def find(self,x):
    if self.parents[x]==x:
      return x
    else:
      self.parents[x]=self.find(self.parents[x])
      return self.parents[x]

  def unite(self,x,y):
    x=self.find(x)
    y=self.find(y)
    if x!=y:
      if self.rank[x]<self.rank[y]:
        self.sizes[y]+=self.sizes[x]
        self.parents[x]=y
      else:
        self.sizes[x]+=self.sizes[y]
        self.parents[y]=x
        if self.rank[x]==self.rank[y]:
          self.rank[x]+=1
  def same(self,x,y):
    return self.find(x)==self.find(y)

  def get_parents(self):
    for n in range(self.nodes):
      self.find(n)
    return self.parents

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

ans=0
for i in range(M):
  uf = UnionFind(N)
  for j in range(M):
    if i==j:
      continue
    uf.unite(*adj[j])  
  if len(set(uf.get_parents()))!=1:
    ans += 1
print(ans)

import copy
N, M = map(int, input().split())
l = []
for i in range(M):
  l.append(list(map(int, input().split())))
  
def bfs(l, tmp, came):
  t = []
  for n in tmp:
    for s in l:
      if (s[0]==n) and (s[1] not in came):
        t.append(s[1])
        came.append(s[1])
      elif (s[1]==n) and (s[0] not in came):
        t.append(s[0])
        came.append(s[0])
  if t == []:
    came = set(came)
    return came
  else:
    return bfs(l, t, came)
  
ans = 0
for i in range(M):
  x = copy.copy(l)
  x.pop(i)
  a = bfs(x, [1], [1])
  if len(a) < N:
    ans += 1
print(ans)

class union_find():
    def __init__(self, n):
        # self.n = n
        self.root = [-1]*(n+1)
        self.rank = [0]*(n+1)
        self.siz = n

    def find_root(self, x):
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find_root(self.root[x])
            return self.root[x]

    def unite(self, x, y):
        x = self.find_root(x)
        y = self.find_root(y)
        if x == y:
            return
        elif self.rank[x] > self.rank[y]:
            self.root[x] += self.root[y]
            self.root[y] = x
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1
        self.siz -= 1

    def same(self, x, y):
        return self.find_root(x) == self.find_root(y)

    def size(self):
        return self.siz


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

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

g = union_find(n)
ans = 0
for i in range(len(ab)):
    for j in range(len(ab)):
        if i == j:
            continue
        a, b = ab[j]
        g.unite(a, b)

    if g.size() != 1:
        ans += 1
    g = union_find(n)


print(ans)


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

edge = []
graph = [[] for _ in range(N)]
for _ in range(M):
    a, b = [int(x) - 1 for x in input().split()]
    edge.append((a, b))
    graph[a].append(b); graph[b].append(a)

def dfs(now):
    searched[now] = True
    for next in graph[now]:
        if searched[next]:
            continue
        if min(now, next) == a and max(now, next) == b:
            continue
        dfs(next)

ans = M
for i in range(M):
    a, b = edge[i]
    searched = [False] * N
    dfs(0)
    if sum(searched) == N:
        ans -= 1

print(ans)


#!/usr/bin/env python
# coding: utf-8

# In[1]:


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

def dfs(pos):
  if visit[pos] == 1:
    return
  visit[pos] = 1
  
  for i in range(n):
    if graph[pos][i] == 1:
      dfs(i)

count = 0
for hen in range(m):
  graph = [[0]*n for i in range(n)]
  visit = [0]*n

  for i in range(m):
    pos1 = data[i][0] - 1
    pos2 = data[i][1] - 1
    if i != hen:
      graph[pos1][pos2] = 1
      graph[pos2][pos1] = 1
  dfs(0)
  connected = True
  for i in range(n):
    if visit[i] == 0:
      connected = False
  if not connected:
    count += 1
print(count)


# In[ ]:






#Union Find

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        tank = []
        while par[x] >= 0:
            tank.append(x)
            x = par[x]
        for elt in tank:
            par[elt] = x
        return x
#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定
def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数
def size(x):
    return -par[find(x)]

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

    edge.append([a,b])


ans=0
for j in range(m):
    #初期化 
    #根なら-size,子なら親の頂点
    par = [-1]*n
    cnt=0
    for p in range(m):
        if p==j:
            continue
    
        e=edge[p]
        unite(e[0],e[1])  
          
    for k in range(n):
        if par[k]<0:
            cnt+=1

    if cnt>=2:
        ans+=1
    
    

    


print(ans)



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

for i in range(M):
    ab[i][0], ab[i][1] = map(int, input().split())
    to1[ab[i][0]-1].append(ab[i][1]-1)
    to1[ab[i][1]-1].append(ab[i][0]-1)

ans = 0

def DFS(n):
    nonlocal v
    if v[n] == 1:
        return
    v[n] = 1
    for i in to1[n]:
        DFS(i)

for i in range(M):
    v = [0] * N
    p = ab[i]
    p[0] -= 1
    p[1] -= 1
    to1[p[0]].remove(p[1])
    to1[p[1]].remove(p[0])
    DFS(0)
    if sum(v) != N:
        ans += 1
    to1[p[0]].append(p[1])
    to1[p[1]].append(p[0])

print(ans)

import copy

def main():
	N, M = [int(n) for n in input().split(" ")]
	edges = [[] for i in range(N)]
	# edges[i] : edges from vertex i 
	r = []
	for i in range(M):
		a, b = [int(x) for x in input().split(" ")]
		edges[a - 1].append(b - 1)
		edges[b - 1].append(a - 1)
		r.append([a - 1, b - 1])
	cnt = 0
	for i in range(len(r)):
		if not isConnected(edges, r[i]):
			cnt += 1
	print(cnt)

def isConnected(edges, remove_edge):
	n_v = len(edges)
	checked = [0] * n_v
	to_check = [0]
	e = copy.deepcopy(edges)
	e[remove_edge[0]].remove(remove_edge[1])
	e[remove_edge[1]].remove(remove_edge[0])
	while len(to_check) > 0:
		checking = to_check.pop(0)
		checked[checking] = 1
		for i in e[checking]:
			if checked[i] == 1:
				continue
			else:
				to_check.append(i)
	if n_v == sum(checked):
		return True
	else:
		return False


main()

n, m = map(int, input().split())
list_AB = [ list(map(int,input().split(" "))) for _ in range(m)]
ans = 0

for i in range(m):
    route = [[] for _ in range(n)]
    for j in range(m):
        if j != i:
            a, b = list_AB[j][0], list_AB[j][1]
            route[a-1].append(b-1)
            route[b-1].append(a-1)

    q = [0]
    l = {0}

    while q:
        x = q.pop(0)
        for p in route[x]:
            if p not in l:
                l.add(p)
                q.append(p)

    if len(list(l)) != n:
        ans += 1

print(ans)

N,M = list(map(int,input().split()))
G = [[] for _ in range(N)]
H = []
for i in range(M):
  a,b = list(map(int,input().split()))
  a-=1;b-=1 #0index
  G[a].append([b,i]);G[b].append([a,i]) #iを辺のIDとして保存
  H.append([a,b])
ans = 0

def dfs(v,ID): #IDの辺を使えない
  visited.add(v)
  for u,idx in G[v]:
    if idx == ID or u in visited:
      continue
    dfs(u,ID)

for i in range(M):
  visited = set([])
  start = H[i][0]
  goal = H[i][1]
  dfs(start,i)
  if goal not in visited:
    ans +=1
print(ans)


from collections import Counter
N, M = map(int, input().split())

class UnionFind:
    def __init__(self, N):
        self.root = list(range(N + 1))
        self.size = [1] * (N + 1)

    def __getitem__(self, x):
        root = self.root
        while root[x] != x:
            root[x] = root[root[x]]
            x = root[x]
        return x

    def merge(self, x, y):
        x = self[x]
        y = self[y]
        if x == y:
            return
        sx, sy = self.size[x], self.size[y]
        if sx < sy:
            x, y = y, x
            sx, sy = sy, sx
        self.root[y] = x
        self.size[x] += sy


A, B = [], []
for i in range(M):
    a, b = map(int, input().split())
    A.append(a)
    B.append(b)

count = 0
for i in range(M):
    uni = UnionFind(N)
    for j in range(M):
        if j == i:
            continue
        uni.merge(A[j], B[j])
    # UnionFindの連結成分の個数を数える
    roots = [uni[x] for x in uni.root[1:]]
    counter = Counter(roots)
    if len(counter) > 1:
        count += 1

print(count)

class UnionFind():
    def __init__(self,n):
        self.parents = [-1]*n
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x
        

N,M = map(int, input().split())
AB = []
for _ in range(M):
    AB.append(list(map(int, input().split())))
ans = 0
for i in range(M):
    if i == M-1:
        ab = AB[:M-1]
    else:
        ab = AB[:i]+AB[i+1:]
    uf = UnionFind(N)
    for j in ab:
        uf.union(j[0]-1,j[1]-1)
    if uf.parents[uf.find(0)] != - N:
        ans += 1
print(ans)

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

for i in range(M):
  a, b = map(int, input().split())
  a, b = a-1, b-1
  graph[a].append(b)
  graph[b].append(a) 
    
def dfs(x,g):
    if vis[x]:return
    vis[x]=1
    for i in g[x]:
     dfs(i,g)
    return

ans=0
for i in range(len(graph)):
    for j in range(len(graph[i])):
        t=graph[i]
        gn=graph[0:i]+[t[0:j]+t[j+1:]]+graph[i+1:]
        vis=[0]*N
        dfs(0,gn)
        if not(all(vis)):
            # print(i+1, graph[i][j]+1,gn,vis)
            ans+=1
print(ans)

n,m = map(int, input().split())
reach = [0]*(n+1)
l = [[] for i in range(n+1)]
for i in range(m):
  a,b = map(int, input().split())
  l[a].append(b)
  l[b].append(a)
  
def dfs(s, parent):
  reach[s] = 1
  for i in l[s]:
    if i == parent: continue
    if reach[i] == 0:
      dfs(i, s)
    else:
      reach[i] += 1

loop = [0]*(n+1)
for i in range(1, n+1):
  reach = [0]*(n+1)
  dfs(i, 0)
  if reach[i] != 1:
    loop[i] = 1
ans = 0
for i in range(1, n+1):
  for j in l[i]:
    if loop[i] == 1 and loop[j] == 1:
      ans += 1
print(m - ans//2)


class node:
    def __init__(self, id):
        self.id = id
        self.root = self

    def findRoot(self):
        if self == self.root:
            return self
        else:
            self.root = self.root.findRoot()
            return self.root

    def resetRoot(self):
        self.root = self

class Tree:
    def __init__(self, num):
        self.nodes = {i:node(i) for i in range(num)}

    def union(self, one, other):
        root1 = one.findRoot()
        root2 = other.findRoot()
        root1.root = root2.root = self.nodes[min(root1.id, root2.id)]

    def resetTree(self):
        for n in self.nodes.values():
            n.resetRoot()

    def makeTree(self, Edge):
        self.edge = Edge
        for x,y in Edge:
            self.union(self.nodes[x-1], self.nodes[y-1])


def main():
    with open(0) as f:
        N, M = map(int, f.readline().split())
        Edge = [tuple(map(int, line.split())) for line in f.readlines()]
    
    tree = Tree(N)
    ans = 0
    for i in range(M):
        edge = [v for  v in Edge if v != Edge[i]]
        tree.makeTree(edge)
        if any(x.findRoot().id != 0 for x in tree.nodes.values()):
            ans += 1
        tree.resetTree()
    print(ans)

def __starting_point():
    main()
__starting_point()

import copy
N,M=map(int,input().split())
path_matrix=[[0 for i in range(N)] for j in range(N)]
L=[[] for i in range(M)]

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

color_white=["W" for i in range(N)]
color_black=["B" for i in range(N)]
visited=copy.deepcopy(color_white)

def path(x,y):
    path_matrix[x-1][y-1]=0
    path_matrix[y-1][x-1]=0
    return DFS(x,path_matrix)

def DFS(x,tim):
    visited[x-1]="B"
    if visited==color_black:
        return True
    total_ans=0
    for i in range(N):
        if tim[x-1][i]==1 and visited[i]=="W":
            total_ans=int(DFS(i+1,tim))

    return total_ans
    
ans=0
for i in range(M):
    visited=copy.deepcopy(color_white)
    if path(L[i][0],L[i][1])==0:
        ans+=1
    path_matrix[L[i][0]-1][L[i][1]-1]=1
    path_matrix[L[i][1]-1][L[i][0]-1]=1

print(ans)

import itertools
#入力
N,M = list(map(int, input().split()))
ABs = [list(map(int, input().split())) for _ in range(M)]

#橋はMAX50本なので、1本ずつ取り除いて全てが繋がるかどうかを試行する。

#UnionFind木


def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x]) #経路圧縮
        return par[x]
def same(x,y):
    return find(x) == find(y)
def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
    size[y] = size[x] + size[y]
    size[x] = 0

#橋の組み合わせ
loop_list = list(itertools.combinations(ABs, M-1))
#print(loop_list)

ans = 0
for loop in loop_list:
    #ループ毎にリセットするので。良くない気がする。
    par = [i for i in range(N+1)]
    size = [1 for _ in range(N+1)]

    for bridge in loop:
        unite(bridge[0], bridge[1])
    
#    print(par)
#    print(size)
    if(max(size) != N):
        ans += 1

print(ans)

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

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

ans=0
for i in range(M):
    uf=UnionFind(N)
    for j in range(M):
        if i==j:
            continue
        a,b=ab[j]
        uf.union(a-1,b-1)
    ans+=(uf.group_count()>1)
print(ans)

from collections import deque
number,m = list(map(int,input().split()))

h = deque([])

for _ in range(m):
    l = list(map(int,input().split()))
    h.append(l)
count = 0

for i in range(m):
    if i != 0:
        h.append([a1,b1])
    a1,b1 = h.popleft()
    g = [[] for _ in range(number)]
    for a,b in h:

        g[a-1].append(b)
        g[b-1].append(a)

    q = deque([a1])
    pre = [0]*number
    pre[a1-1] = 1
    while q:
        now = q.popleft()

        for n in g[now-1]:

            if pre[n-1] == 0:
                q.append(n)
                pre[n-1] = 1
            else:
                continue
    
    if sum(pre) != number:
        count+=1

print(count)



class UnionFind():
  def __init__(self,n):
    self.n = n
    self.parents = [-1]*n
  def find(self,x):
    if self.parents[x]<0:
      return x
    else:
      self.parents[x]=self.find(self.parents[x])
      return self.parents[x]
  def unite(self,x,y):
    x = self.find(x)
    y = self.find(y)
    if x == y:
      return
    if self.parents[x]>self.parents[y]:
      x,y=y,x
    self.parents[x]+=self.parents[y]
    self.parents[y]=x
  def same(self,x,y):
    return self.find(x)==self.find(y)
N,M = map(int,input().split())
A = [0]*M
t=0
B=[0]*M
for i in  range(M):
  a,b=map(int,input().split())
  A[i]=[a-1,b-1]
for t in range(M):
  UF = UnionFind(N)
  for i in range(M):
    if i!=t:
      UF.unite(A[i][0],A[i][1])
  if UF.same(A[t][0],A[t][1])==False:
    B[t]=1
print(sum(B))

class UnionFind():
    def __init__(self, n):
        self.parents = list(range(n))
        self.size = [1] * n
    def find(self, x):
        if self.parents[x] == x:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.size[x] < self.size[y]:
            self.size[y] += self.size[x]
            self.parents[x] = y
        else:
            self.size[x] += self.size[y]
            self.parents[y] = x
    def size(self, x):
        return -self.parents[self.find(x)]
    def same(self, x, y):
        return self.find(x) == self.find(y)
    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]
    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]
    def group_count(self):
        return len(self.roots())
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())
n,m=list(map(int,input().split()))
num=[list(map(int,input().split())) for _ in range(m)]
ans=0
for i in range(m):
    uf=UnionFind(n)
    for j in range(m):
        if i!=j:
            uf.union(num[j][0]-1,num[j][1]-1)
    if uf.size[uf.find(0)]!=n:
        ans+=1
print(ans)


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

n, m = map(int, input().split())
a = [list(map(int, input().split())) for i in range(m)]
ans = 0
for i in range(m):
    uf = UnionFind(n)
    for j in range(m):
        if i != j:
            uf.union(a[j][0]-1, a[j][1]-1)
    if uf.size(0) != n:
        ans += 1
print(ans)

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

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y

cnt = 0
for i in range(M):
    par = [i for i in range(N+1)]
    k = 0
    for a, b in AB:
        if k != i:
            unite(a,b)
        k += 1
    
    res = []
    for j in range(1,N+1):
        res.append(find(j))
    
    if len(set(res)) >= 2:
        cnt += 1
print(cnt)


class UnionFind:
    def __init__(self, N):
        self.N = N

        # the parent of all node is itself
        # self.parent = list(range(N))
        self.parent = [-1] * N

    def root(self, i):
        if self.parent[i] < 0:
            return i

        r = self.root(self.parent[i])
        self.parent[i] = r
        return r

    def unite(self, i, j):
        i = self.root(i)
        j = self.root(j)

        if i == j:
            return

        if i > j:
            i, j = j, i

        self.parent[i] += self.parent[j]
        self.parent[j] = i
        # print(self.parent)

    def same(self, i, j):
        return self.root(i) == self.root(j)

    def size(self, i):
        return -self.parent[self.root(i)]

    def roots(self):
        return [self.root(i) for i in range(self.N)]

    def groupcount(self):
        return len(set(self.roots()))

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

ans = 0

# 全てのedgeに対して
for i in range(M):
    # UnionFind木を初期化
    forest = UnionFind(N)

    # i番目のエッジを除いたものをつなぐ
    for i, j in edges[:i] + edges[i+1:]:
        forest.unite(i, j)

    # 全てのノードがつながっている <=> グループ数は1
    # グループ数（島の数）が１ではない <=> グラフは２つ以上の島から成る
    if forest.groupcount() != 1:
        ans += 1

print(ans)

from collections import deque
from sys import stdin
input = stdin.readline

class Unionfind():
    def __init__(self, n):
        self.n = n
        self.parent = [-1]*n
    
    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        
        if x == y:
            return
        if self.parent[x] < self.parent[y]:
            x,y = y,x
        
        self.parent[x] += self.parent[y]
        self.parent[y] = x
        

N,M = map(int, input().split())
A = [-1]*M; B = [-1]*M
for i in range(M):
    a,b = map(lambda x: int(x) - 1, input().split())
    A[i] = a; B[i] = b

ans = 0
for exclude_idx in range(M):
    uf = Unionfind(N)
    for i in range(M):
        if i == exclude_idx:
            continue
        uf.union(A[i],B[i])
    
    cnt = 0
    for parent in uf.parent:
        if parent < 0:
            cnt += 1
    if cnt >= 2:
        ans += 1

print(ans)

class UnionFind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [1 for i in range(n)]

    def root(self, x):
        if self.parent[x] == x:
            return x
        else:
            self.parent[x] = self.root(self.parent[x])
            return self.parent[x]

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x != y:
            self.parent[x] = y
            self.size[y] += self.size[x]

    def same(self, x, y):
        return self.root(x) == self.root(y)

    def count(self, x):
        return self.size[self.root(x)]

N, M = list(map(int, input().split()))
AB = [list([int(x)-1 for x in input().split()]) for _ in range(M)]
ans = 0
for i in range(M):
    un = UnionFind(N)
    for j in range(M):
        if i != j:
            un.unite(AB[j][0], AB[j][1])
    if un.count(0) != N:
        ans += 1
print(ans)


n,m = map(int, input().split())
s =[set() for i in range(n)]
e = []
for i in range(m):
  a,b = map(int, input().split())
  a-=1
  b-=1
  s[a].add(b)
  s[b].add(a)
  e.append([a,b])
def dfs(u,v,c):
  visited[u] = 1
  c += 1
  if u == v:
    d.append(c)
    return True
  for i in s[u]:
    if visited[i]:
      continue
    if c == 1:
      if i == v:
        continue
    dfs(i,v,c)

cnt = 0
for i in range(m):
  x,y = e[i][0],e[i][1]
  visited = [0 for i in range(n)]
  d = []
  dfs(x,y,0)
  if len(d) > 0:
    cnt += 1
print (m-cnt)

class UnionFind():
  def __init__(self,n):
    self.n=n
    self.parents =[-1]*n

  def find(self, x):
    if self.parents[x]<0:
      return x
    else:
      self.parents[x]=self.find(self.parents[x])
      return self.parents[x]

  def union(self, x, y):
    x=self.find(x)
    y=self.find(y)
    if x==y:
      return
    if self.parents[x]>self.parents[y]:
      x,y=y,x
    self.parents[x]+=self.parents[y]
    self.parents[y]=x
    
  def size(self, x):
    return -self.parents[self.find(x)]

  def same(self, x, y):
    return self.find(x)==self.find(y)

  def members(self, x):
    root=self.find(x)
    return list(i for i in range(self.n) if self.find(i) == root)

  def roots(self):
    return list(i for i, x in enumerate(self.parents) if x < 0)

  def group_count(self):
    return len(self.roots)

  def all_group_members(self):
    return {r: self.members(r) for r in self.roots()}

  def __str__(self):
    return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

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

ans = 0
for i in range(M):
  uf = UnionFind(N)
  for j in range(M):
    if i == j:
      continue
    uf.union(*adj[j])
  if len(set(uf.roots()))!=1:
    ans += 1
print(ans)

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x): #親を返す
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y): #和集合の生成
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x): #所属する集合の大きさ
        return -self.parents[self.find(x)]

    def same(self, x, y): #同じ集合に属しているか判定
        return self.find(x) == self.find(y)

    def members(self, x): #同じ集合に属する要素全列挙
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self): #集合のリーダー全列挙
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self): #集合の数
        return len(self.roots())

    def all_group_members(self): #辞書型,{(リーダーの番号):(その集合の要素全列挙)}
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

n,m=map(int,input().split())
l=[]
for i in range(m):
    l.append(list(map(int,input().split())))
ans=0
for i in range(m):
    a=UnionFind(n)
    for j in range(m):
        if i==j:
            continue
        a.union(l[j][0]-1,l[j][1]-1)
    if a.group_count()==2:
        ans+=1
print(ans)

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 12 00:49:45 2020

@author: liang
"""
from collections import deque

def isBridge(start, goal):
    visited = [False]*N
    q = deque()
    q.append(start)
    visited[start] = True
    while q:
        cur = q.popleft()
        if cur == goal:
            return False
        for nex in adj[cur]:
            if not visited[nex]:
                visited[nex] = True
                q.append(nex)
    return True     

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


for i in range(N):
    adj.append(list())

E = list()
for i in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    E.append((a,b))
    adj[a].append(b)
    adj[b].append(a)
ans = 0
for e in E:
    a, b = e
    adj[a].remove(b)
    adj[b].remove(a)
    if isBridge(a,b):
        ans += 1
    adj[a].append(b)
    adj[b].append(a)
print(ans)

from itertools import combinations

class unionfind:
    def __init__(self,n):
        self.par=[i for i in range(n)]
        self.rank=[1]*n

    def root(self,a):
        if self.par[a]==a : return a
        parent=self.root(self.par[a])
        self.par[a]=parent
        return parent

    def unite(self,a,b):
        ra,rb=self.root(a),self.root(b)
        if ra==rb : return
        if self.rank[ra]>self.rank[rb]:
            ra,rb=rb,ra
        self.par[rb]=ra
        self.rank[ra]+=1

    def same(self,a,b):
        return self.root(a)==self.root(b)


def main():
    n,m=map(int,input().split())
    edges=[tuple(map(int,input().split())) for _ in range(m)]

    sm=0
    for e_remove in edges:
        uf=unionfind(n)
        for e in edges:
            if e==e_remove : continue
            uf.unite(e[0]-1,e[1]-1)

        for a in combinations(range(n),2):
            if not uf.same(a[0],a[1]):
                break
        else : continue
        sm+=1

    print(sm)

main()

N,M = map(int,input().split())
s = [[] for i in range(N)]
m = []
for i in range(M):
    a,b = map(int,input().split())
    s[a-1].append(b)
    s[b-1].append(a)
    m.append([a,b])
ans = 0
from collections import deque
import copy
d = deque()
for i in range(M):
    n = [0] * N
    a = m[i][0]
    b = m[i][1]
    c = s[a-1].copy()
    c.remove(b)
    d.append(c)
    n[a-1] = 1
    while len(d) > 0:
        e = d.popleft()
        for j in e:
            if n[j-1] == 0:
                n[j-1] = 1
                d.append(s[j-1])
    if 0 in n:
        ans += 1
print(ans)

def root(i):
    if par[i] < 0:
        return i
    else:
        return root(par[i])

def size(a):
    return -par[root(a)]

def union(a,b):
    a = root(a)
    b = root(b)
    if a == b:#親が等しい
        return False
    if size(a) < size(b):#サイズが大きい方に繋げる
        a,b = b,a
    par[a] += par[b]
    par[b] = a
    return True

n,m = map(int,input().split())
bridge = []
for i in range(m):
    bridge.append([int(j)-1 for j in input().split()])
ans = 0
for i in range(m):
    par = [-1 for _ in range(n)]
    for j in range(m):
        if j != i:
            union(bridge[j][0],bridge[j][1])
    cnt = [ i for i in par if i < 0]
    if len(cnt) > 1:
        ans += 1
print(ans)

class UnionFind():
    def __init__(self,N):
        self.par=[-1]*N
    
    def unite(self,x,y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return False
        if self.par[x] > self.par[y]:
            x,y = y,x
        self.par[x] += self.par[y]
        self.par[y] = x
        return True
    
    def root(self,x):
        if self.par[x]<0:
            return x
        self.par[x] = self.root(self.par[x])
        return self.par[x]
    
    def size(self,x):
        return -self.par[self.root(x)]

N,M = map(int,input().split())
Edge = []
for _ in range(M):
    u,v = map(int,input().split())
    Edge.append((u-1,v-1))

ans = 0

for e in Edge:
    uf = UnionFind(N)
    for _e in Edge:
        if e == _e:
            continue
        uf.unite(_e[0],_e[1])
    if uf.size(0) != N:
        ans += 1

print(ans)

import copy
import sys
sys.setrecursionlimit(10**7)

N, M = map(int, input().split())
G = [[] for _ in range(N)]
side = []
for _ in range(M):
    a, b = map(int, input().split())
    a -= 1; b -= 1
    G[a].append(b)
    G[b].append(a)
    side.append((a,b))

def dfs(v,G):
    seen[v] = True
    for next_v in G[v]:
        if seen[next_v] == True:
             continue
        dfs(next_v,G)

bridge = 0
# 各辺を取り除く
for a,b in side:
    Gc = copy.deepcopy(G)
    Gc[a].remove(b)
    Gc[b].remove(a)
    seen = [False]*N
    cnt = 0
    # 連結成分のカウント
    for s in range(N):
        if seen[s] == True:
            continue
        cnt += 1
        dfs(s,Gc)
    # 連結成分が 2 個以上ならその辺は橋    
    if cnt>=2:
        bridge += 1
print(bridge)

import copy
from collections import deque
N,M = map(int,input().split())
lsside = [[] for i in range(N+1)]
lsline = []
for i in range(M):
    a,b = map(int,input().split())
    lsside[a].append(b)
    lsside[b].append(a)
    lsline.append([a,b])

ans = 0
lsloop = []
for i in range(M):
    graph = copy.deepcopy(lsside)
    a = lsline[i][0]
    b = lsline[i][1]
    graph[a].remove(b)
    graph[b].remove(a)
    used = [False for i in range(N+1)]
    ii = 1
    d = deque()
    d.append(a)
    used[a] = True
    while d:
        v = d.popleft()
        for i in graph[v]:
            if used[i]:
                continue
            ii += 1
            d.append(i)
            used[i] = True
    lsloop.append(ii)
ans = M - lsloop.count(N)
print(ans)

from collections import deque
N, M = map(int, input().split())

h = [[]*N for _ in range(N)]
AB = []

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

ans = 0

for i in range(M):
    a, b = AB[i]
    h[a].remove(b)
    h[b].remove(a)
    
    fl = [False]*N

    q = deque([0])
    while q:
        t = q.popleft()
        if fl[t]:
            continue
        fl[t] = True
        for tt in h[t]:
            q.append(tt)
    
    if not all(fl):
        ans += 1

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

print(ans)

import queue
n, m = list(map(int, input().split()))
route = [[] for _ in range(n)]
vals = []
for _ in range(m):
    a, b = list(map(int, input().split()))
    route[a-1].append(b-1)
    route[b-1].append(a-1)
    vals.append([a-1, b-1])
ans = m
for i in range(m):
    route2 = set()
    q = queue.Queue()
    q.put(0)
    route[vals[i][0]].remove(vals[i][1])
    route[vals[i][1]].remove(vals[i][0])
    while not q.empty():
        a = q.get()
        if not a in route2:
            route2.add(a)
            for j in route[a]:
                q.put(j)
        if len(route2) == n:
            ans -= 1
            break
    route[vals[i][0]].append(vals[i][1])
    route[vals[i][1]].append(vals[i][0])
print(ans)
        


class union_find():
    def __init__(self,n):
        self.n=n
        ##親要素のノード番号を格納。par[x]==xのときそのノードは根
        ##親とはその上にノードなし！！　
        self.par=[i for i in range(n+1)]
        self.rank=[0]*(n+1)

    def find(self,x):
        if self.par[x]==x:
            return x
        else:
            self.par[x]=self.find(self.par[x])
            return self.par[x]

    def union(self,x,y):
        x=self.find(x)
        y=self.find(y)

        ##木の高さを比較し、低い方から高い方へ辺をはる

        if self.rank[x]<self.rank[y]:
          self.par[x]=y
        else:
          self.par[y]=x
          ##同じなら片方を伸ばす
          if self.rank[x]==self.rank[y]:
            self.rank[y]+=1

    def same(self,x,y):
        return self.find(x) == self.find(y)
      
n,m=map(int,input().split())
uf=union_find(n)
ans=0
s=[]
for _ in range(m):
  a=list(map(int,input().split()))
  s.append(a)
  uf.union(a[0],a[1])
  
  

for e in range(m):
  uf1=union_find(n)
  ch=0
  for d in range(m):
    if d!=e:
      uf1.union(s[d][0],s[d][1])
      
  for i in range(1,n):
    for j in range(i+1,n+1):
      if not uf1.same(i,j):
        ch+=1
  if ch>0:
    ans+=1

    
print(ans)

# Union Find
# xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]


# xとyの属する集合の併合
def unite(x, y):
    x = find(x)
    y = find(y)

    if x == y:
        return False
    else:
        # x < y にする
        if par[x] > par[y]:
            x, y = y, x
        par[x] += par[y]
        par[y] = x
        return True


# 根の個数を返す
def group_count():
    return sum(x < 0 for x in par)


n, m = map(int, input().split())
l = []
for _ in range(m):
    l.append(tuple(map(int, input().split())))

ans = 0
for j in range(m):
    par = [-1] * n
    for i, ab in enumerate(l):
        if i != j:
            unite(ab[0] - 1, ab[1] - 1)
    if group_count() == 2:
        ans += 1

print(ans)

n , m = list(map(int, input().split()))
c = [[0]*n for i in range(n)]
for i in range(m):
    a , b = list(map(int, input().split()))
    c[a-1][b-1]=1
    c[b-1][a-1]=1
ans = 0
for k in range(n):
    for i in range(n):
        if sum(c[i])==1:
            ans+=1
            for j in range(n):
                if c[i][j]==1:
                    c[i][j]=0
                    c[j][i]=0
print(ans)


from networkx import *
n, m = map(int, input().split())
a = [list(map(int, input().split())) for _ in range(m)]
g = Graph(a)
print(len(tuple(bridges(g))))

from collections import deque

n, m = list(map(int, input().split()))
graph = [[] for i in range(n)]
for i in range(m):
    u, v = list(map(int, input().split()))
    u -= 1
    v -= 1
    graph[u].append([i,v])
    graph[v].append([i,u])
    
cnt = 0
for i in range(m):
    d = deque()
    d.append(0)
    visited = [False]*n
    visited[0] = True
    while d:
        cf = d.pop()
        for ci, ct in graph[cf]:
            if ci == i:
                continue
            if not visited[ct]:
                d.append(ct)
                visited[ct] = True
    if False in visited:
        cnt += 1
print(cnt)


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

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

for i in range(M):
    uf = UnionFind(N)
    for j in range(M):
        if i == j:
            continue
        uf.union(ab_list[j][0], ab_list[j][1])
    if not uf.same(ab_list[i][0], ab_list[i][1]):
        ans += 1
print(ans)


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

def lowlink(g, root=0):
    n = len(g)
    order = [n]*n
    low = [n]*n

    s = [root]
    cnt = 1
    par = [-1]*n
    seq = []
    while s:
        v = s.pop()
        if order[v] != n:
            continue
        order[v] = cnt
        seq.append(v)
        low[v] = cnt
        cnt += 1
        for u in g[v]:
            if order[u] < cnt:
                if par[v] != u:
                    low[v] = min(low[v], order[u])
                    continue
            else:
                par[u] = v
                s.append(u)
    child = [[] for _ in range(n)]
    for v in range(n):
        if par[v] != -1:
            child[par[v]].append(v)
    seq.reverse()
    for v in seq:
        for u in child[v]:
            low[v] = min(low[v], low[u])
    # bridge
    bridge = []
    for p in range(n):
        for c in child[p]:
            if order[p] < low[c]:
                bridge.append((p, c))

    # articulation points
    AP = []
    for v in range(n):
        if v == root:
            if len(child[v]) >= 2:
                AP.append(v)
        else:
            for c in child[v]:
                if order[v] <= low[c]:
                    AP.append(v)
                    break
    return AP, bridge

_, bridge = lowlink(g, 0)
print(len(bridge))

class UnionFind:
    def __init__(self, n):
        self._n = n
        self._table = [-1]*n

    def _root(self, x):
        stack = []
        while self._table[x] >= 0:
            stack.append(x)
            x = self._table[x]
        for y in stack:
            self._table[y] = x
        return x
    
    def unite(self, x, y):
        x, y = self._root(x), self._root(y)
        if x == y:
            return
        if x > y:
            x, y = y, x
        self._table[x] += self._table[y]
        self._table[y] = x
    
    def same(self, x, y):
        return self._root(x) == self._root(y)

    def count_members(self, x):
        return -self._table[self._root(x)]
    
    def count_groups(self):
        return len({self._root(i) for i in range(self._n)})
    
    def __str__(self):
        return str([self._root(i) for i in range(self._n)])
    
    def __repr__(self):           
        return repr([self._root(i) for i in range(self._n)])

n, m, *AB = map(int, open(0).read().split())
ans = 0
for i in range(m):
    uf = UnionFind(n)
    for j, (a, b) in enumerate(zip(AB[::2], AB[1::2])):
        if i == j:
            continue
        uf.unite(a-1, b-1)
    ans += uf.count_groups() != 1
print(ans)

class UnionFind():
  def __init__(self,n):
    self.parents=[-1]*n
  
  def find(self,x):
    if self.parents[x]<0:
      return x
    self.parents[x]=self.find(self.parents[x])
    return self.parents[x]
  
  def union(self,x,y):
    x = self.find(x)
    y = self.find(y)
    if x==y:
      return
    
    if self.parents[x]>self.parents[y]:
      x,y=y,x
    
    self.parents[x]+=self.parents[y]
    self.parents[y]=x

N,M=map(int,input().split())
ans=0
A=[]
B=[]

for _ in range(M):
  a,b=map(int,input().split())
  A.append(a)
  B.append(b)
  
for i in range(M):
  uf=UnionFind(N+1)
  for j in range(M):
    if i==j:
      continue
    uf.union(A[j],B[j])
  else:
    if abs(min(uf.parents[1:]))!=N:
      ans+=1
print(ans)

import networkx as nx

n, m, *AB = map(int, open(0).read().split())
G = nx.Graph()
G.add_edges_from(zip(AB[::2], AB[1::2]))
print(len(list(nx.bridges(G))))

import sys
sys.setrecursionlimit(10 ** 9)
# input = sys.stdin.readline    ####
def int1(x): return int(x) - 1
def II(): return int(input())
def MI(): return list(map(int, input().split()))
def MI1(): return list(map(int1, input().split()))
def LI(): return list(map(int, input().split()))
def LI1(): return list(map(int1, input().split()))
def LLI(rows_number): return [LI() for _ in range(rows_number)]
def MS(): return input().split()
def LS(): return list(input())
def LLS(rows_number): return [LS() for _ in range(rows_number)]
def printlist(lst, k=' '): print((k.join(list(map(str, lst)))))
INF = float('inf')
# from math import ceil, floor, log2
from collections import deque, defaultdict
# from itertools import combinations as comb, combinations_with_replacement as comb_w, accumulate, product, permutations
# from heapq import heapify, heappop, heappush
# import numpy as np    # cumsum
# from bisect import bisect_left, bisect_right

def solve():
    N, M = MI()
    V = [[] for _ in range(N)]
    E = []
    for i in range(M):
        a, b = MI1()
        V[a].append(b)
        V[b].append(a)
        E.append((a, b))

    ans = 0
    for a, b in E:
        used = [0] * N
        flag = True
        q = deque([a])
        used[a] = 1
        while q:
            cur = q.popleft()

            for nv in V[cur]:
                if (a, b) == (cur, nv) or (a, b) == (nv, cur):
                    continue

                if used[nv]:
                    continue

                if nv == b:
                    flag = False
                    q = []
                    break

                q.append(nv)
                used[nv] = 1
            # print(a, b, q)

        if flag:
            ans += 1
    print(ans)

def __starting_point():
    solve()


__starting_point()

import sys

input = sys.stdin.readline


class UnionFind:
    """Union Find class.

    "Path compression" and "Union by rank" are used.

    References:
        <https://en.wikipedia.org/wiki/Disjoint-set_data_structure>
    """

    def __init__(self, N):
        self.N = N
        self.__make_set()

    def __make_set(self):
        self._parent = list(range(self.N + 1))
        self._rank = [0] * (self.N + 1)
        self._size = [1] * (self.N + 1)

    def find(self, x):
        if self._parent[x] != x:
            self._parent[x] = self.find(self._parent[x])
        return self._parent[x]

    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)

        if x_root == y_root:
            return

        x_rank = self._rank[x_root]
        y_rank = self._rank[y_root]
        if x_rank > y_rank:
            self._parent[y_root] = x_root
            self._size[x_root] += self._size[y_root]
        elif x_rank < y_rank:
            self._parent[x_root] = y_root
            self._size[y_root] += self._size[x_root]
        else:
            self._parent[y_root] = x_root
            self._rank[x_root] += 1
            self._size[x_root] += self._size[y_root]

    def same_set(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return self._size[self.find(x)]


def main():
    N, M = list(map(int, input().split()))
    a = [None] * M
    b = [None] * M
    for i in range(M):
        a[i], b[i] = list(map(int, input().split()))

    ans = 0
    for i in range(M):
        uf = UnionFind(N)
        for j in range(M):
            if j == i:
                continue
            uf.union(a[j], b[j])
        if not uf.same_set(a[i], b[i]):
            ans += 1

    print(ans)


def __starting_point():
    main()

__starting_point()

class UnionFind():    
    def __init__(self, n):
        self.n = n
        self.root = [-1] * n
        self.rnk = [0] * n
        
    def findRoot(self, x):
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.findRoot(self.root[x])  #; print('root[x]', self.root[x])
            return self.root[x]

    def unite(self, x, y):
        x = self.findRoot(x)
        y = self.findRoot(y)
        if x == y:
            return 
        elif self.rnk[x] > self.rnk[y]:
            self.root[y] = x
        else:
            self.root[x] = y
            if self.rnk[x] == self.rnk[y]:
                self.rnk[y] += 1

    def isSame(self, x, y):
        return self.findRoot(x) == self.findRoot(y)


N, M =  map(int, input().split())
edge = [tuple(map(int, input().split())) for _ in range(M)]  #;print(edge)

cnt = 0
for i in range(M):
    uf = UnionFind(N+1)
    for j in range(M):
        if j != i:
            uf.unite(edge[j][0], edge[j][1])
    #print(i, edge[i][0], edge[i][1], uf.isSame(edge[i][0], edge[i][1]))
    if not uf.isSame(edge[i][0], edge[i][1]):
        cnt += 1
print(cnt)

from collections import deque, defaultdict
import sys
sys.setrecursionlimit(2**20)
class LowLink:
    """
    与えられたグラフの関節点と橋を求める
    Attributes:
    size:グラフの頂点
    pre:oreorderでの訪問順
    low: ###1. prenum[u]
         ###2.GのBackEdge(u,v)が存在する場合prenum[v]
         ###3.uをすべての子childに対してlowest[child]
    """
    def __init__(self, v):
        self.size = len(v) + 1
        self.v = v
        self.pre = [None]*self.size
        self.low = [None]*self.size
        self.articulations = []
        self.bridges = []
        for x in range(self.size):
            if self.pre[x] is None:
                self.cnt = 0
                self.dfs(x, None)
    
    def dfs(self, x, prev):
        self.pre[x] = self.low[x] = self.cnt
        self.cnt += 1
        is_articulation = False
        n = 0
        for y in self.v[x]:
            if self.pre[y] is None:
                n += 1
                low_y = self.dfs(y, x)
                if low_y < self.low[x]:
                    self.low[x] = low_y
                if self.pre[x] <= low_y:
                    if self.pre[x]:
                        is_articulation = True
                    if self.pre[x] < low_y:
                        self.bridges.append(
                            (min(x,y), max(x, y))
                        )
            else:
                if y != prev and self.pre[y] < self.low[x]:
                    self.low[x] = self.pre[y]
        if prev is None and n > 1:
            is_articulation = True
        
        if is_articulation:
            self.articulations.append(x)
        
        return self.low[x]

def solve():
    V, E = map(int, input().split())
    G = defaultdict(lambda: [])
    for _ in range(E):
        s, t= map(int, input().split())
        G[s].append(t)
        G[t].append(s)
    
    #initialize
    lowlink = LowLink(G)
    #bridges
    bridges = lowlink.bridges
    print(len(bridges))
 
def __starting_point():
    solve()
__starting_point()

# 幅優先探索で連結成分を求めるプログラム
from collections import deque

# n = int(input())# ノードの数
n, m = map(int, input().split())

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

ans = 0


def bfs(start_node, color_id):  # start_nodeは探索の開始点
    nonlocal color, d
    q = deque([start_node])
    d[start_node] = 0
    color[start_node] = color_id
    while len(q) != 0:
        u = q.popleft()
        for v in adjl[u]:
            if color[v] == NIL:
                d[v] = d[u]+1
                color[v] = color_id
                q.append(v)


#print(l)
for k in range(1, m+1):

    # 隣接リストで格納する
    adjl = [[] for _ in range(n+1)]
    for i in range(1, m+1):  # 隣接関係を受け取る
        if i == k:
            continue
        s, t = l[i-1]
        adjl[s].append(t)
        adjl[t].append(s)

    NIL = -1  # 未発見を示す値
    d = [-1 for i in range(n+1)]  # 頂点1からの距離を格納するリスト
    color = [NIL for i in range(n+1)]  # 未到達かを示すリスト

    #print(adjl)

    color_id = 0
    for u in range(1, n+1):  # node全てからスタートする
        if color[u] == NIL:
            color_id += 1
            bfs(u, color_id)

    #print(color)
    if len(set(color)) >= 3:
        ans += 1
print(ans)

def FindParent(X):
    if Parent[X]==X:
        return X
    else:
        Parent[X] = FindParent(Parent[X])
        return Parent[X]

def CheckParent(X,Y):
    return FindParent(X)==FindParent(Y)

def UniteParent(X,Y):
    X = FindParent(X)
    Y = FindParent(Y)
    if X==Y:
        return 0
    if Rank[X]<Rank[Y]:
        Parent[X] = Y
    else:
        Parent[Y] = X
        if Rank[X]==Rank[Y]:
            Rank[X] += 1

import copy
N,M = (int(T) for T in input().split())
List = [[] for TM in range(0,M)]
for TM in range(0,M):
    List[TM] = [int(T) for T in input().split()]
    
Count = 0
for TM in range(0,M):
    ListCopy = copy.deepcopy(List)
    del ListCopy[TM]
    
    Parent = [I for I in range(N+1)]
    Rank = [0]*(N+1)
    for TTM in range(0,M-1):
        UniteParent(ListCopy[TTM][0],ListCopy[TTM][1])

    if not CheckParent(List[TM][0],List[TM][1]):
        Count += 1
print(Count)

class UnionFind: #引数は頂点の数、1インデックス
    def __init__(self, n):
        self.parents = [i for i in range(n+1)]
        self.rank = [0] * (n+1)

    # 検索
    def find(self, x):
        if self.parents[x] == x:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    # 併合
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if self.rank[x] < self.rank[y]:
            self.parents[x] = y
        else:
            self.parents[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    # 同じ集合に属するか判定
    def same_check(self, x, y):
        return self.find(x) == self.find(y)


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

    count = 0
    for i in range(M):
        union_find = UnionFind(N)
        for j in range(M):
            if i == j:
                continue
            a, b = bridges[j]
            union_find.union(a, b)

        for j in range(1, N):
            if union_find.find(j) != union_find.find(j+1):
                count += 1
                break

    print(count)
        
    







__starting_point()

#
# abc075 c
#
import sys
from io import StringIO
import unittest
from collections import deque


class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)

    def test_入力例_1(self):
        input = """7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7"""
        output = """4"""
        self.assertIO(input, output)

    def test_入力例_2(self):
        input = """3 3
1 2
1 3
2 3"""
        output = """0"""
        self.assertIO(input, output)

    def test_入力例_3(self):
        input = """6 5
1 2
2 3
3 4
4 5
5 6"""
        output = """5"""
        self.assertIO(input, output)


def resolve():
    N, M = list(map(int, input().split()))
    AB = [list(map(int, input().split())) for _ in range(M)]

    ans = 0
    for i in range(M):
        Target = AB[:]
        Target.pop(i)

        G = [[i+1, 0] for i in range(N)]
        for ab in Target:
            a, b = ab
            G[a-1][1] += 1
            G[b-1][1] += 1
            G[a-1].append(b)
            G[b-1].append(a)

        F = [False] * N
        Q = deque()
        Q.append(1)
        F[0] = True

        while Q:
            p = Q.pop()
            if G[p-1][1] == 0:
                continue

            for np in G[p-1][2:]:
                if F[np-1]:
                    continue
                Q.append(np)
                F[np-1] = True

        for f in F:
            if f == False:
                ans += 1
                break

    print(ans)


def __starting_point():
    # unittest.main()
    resolve()

__starting_point()

from typing import List, Tuple


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


def br(n: int, m: int, g: List[Tuple[int, int]]):
    ret = 0
    for i in range(m):
        v = set()
        w = [1]
        while w:
            now = w.pop()
            v.add(now)
            for j, node in enumerate(g):
                if j == i:
                    continue
                if node[0] == now and node[1] not in v:
                    w.append(node[1])
                elif node[1] == now and node[0] not in v:
                    w.append(node[0])
        if len(v) != n:
            ret += 1
    return ret


def __starting_point():
    main()

__starting_point()

from typing import List, Tuple


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


def bb(n: int, m: int, g: List[Tuple[int, int]]):
    ret = 0
    for i in range(m):
        v = set()
        w = [1]
        while w:
            now = w.pop()
            v.add(now)
            for j, node in enumerate(g):
                if j == i:
                    continue
                if node[0] == now and node[1] not in v:
                    w.append(node[1])
                elif node[1] == now and node[0] not in v:
                    w.append(node[0])
        if len(v) != n:
            ret += 1
    return ret


def __starting_point():
    main()

__starting_point()

def FindParent(X):
    if Parent[X]==X:
        return X
    else:
        Parent[X] = FindParent(Parent[X])
        return Parent[X]

def UniteParent(X,Y):
    X = FindParent(X)
    Y = FindParent(Y)
    if X==Y:
        return 0
    if Rank[X]<Rank[Y]:
        Parent[X] = Y
    else:
        Parent[Y] = X
        if Rank[X]==Rank[Y]:
            Rank[X] += 1

import copy
N,M = (int(T) for T in input().split())
List = [[] for TM in range(0,M)]
for TM in range(0,M):
    List[TM] = [int(T) for T in input().split()]
    
Count = 0
for TM in range(0,M):
    ListCopy = copy.deepcopy(List)
    del ListCopy[TM]
    
    Parent = [I for I in range(N+1)]
    Rank = [0]*(N+1)
    for TTM in range(0,M-1):
        UniteParent(ListCopy[TTM][0],ListCopy[TTM][1])
    for TN in range(1,N+1):
        FindParent(TN)
    if len(set(Parent[1:]))>1:
        Count += 1
print(Count)

class UnionFind():
  def __init__(self, n):
    self.n = n
    self.parent = [i for i in range(self.n)]
    self.rank = [0] * self.n
  
  def find_root(self, x):
    if self.parent[x] == x:
      return x
    else:
      self.parent[x] = self.find_root(self.parent[x])
      return self.parent[x]
  
  def unite(self, x, y):
    rx = self.find_root(x)
    ry = self.find_root(y)
    if rx == ry:
      return
    if self.rank[rx] < self.rank[ry]:
      self.parent[rx] = ry
    else:
      self.parent[ry] = rx
      if self.rank[rx] == self.rank[ry]:
        self.rank[rx] += 1
  
  def is_same(self, x, y):
    return self.find_root(x) == self.find_root(y)

N, M = map(int, input().split())
edge = []
bridge = 0
for _ in range(M):
  e = list(map(lambda x: int(x)-1, input().split()))
  edge.append(e)

for i in range(M):
  uf = UnionFind(N)
  for j in range(M):
    if j == i:
      continue
    uf.unite(edge[j][0], edge[j][1])
  if uf.find_root(edge[i][0]) != uf.find_root(edge[i][1]):
    bridge += 1

print(bridge)

N, M = (int(x) for x in input().split())
edge = [tuple(int(x) for x in input().split()) for _ in range(M)]

import numpy as np
from scipy.sparse.csgraph import floyd_warshall
INF = 100
tmpl_graph = [[INF if i != j else 0 for j in range(N)] for i in range(N)]

ans = 0
for E in edge:
    edgeWithoutE = edge.copy()
    edgeWithoutE.remove(E)
    graph = np.array(tmpl_graph)
    for x in edgeWithoutE:
        graph[x[0]-1,x[1]-1] = 1
        graph[x[1]-1,x[0]-1] = 1
    graph = floyd_warshall(graph,directed=False)
    if len(graph[graph == 100]) > 0:
        ans += 1
print(ans)

#https://atcoder.jp/contests/abc075/submissions/15509548

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

def lowlink(g, root=0):
    n = len(g)
    order = [n]*n
    low = [n]*n

    s = [root]
    cnt = 0
    par = [-1]*n
    seq = []
    while s:
        v = s.pop()
        if order[v] != n:
            continue
        order[v] = cnt
        seq.append(v)
        low[v] = cnt
        cnt += 1
        for u in g[v]:
            if order[u] < cnt:
                if par[v] != u:
                    low[v] = min(low[v], order[u])
                    continue
            else:
                par[u] = v
                s.append(u)
    child = [[] for _ in range(n)]
    for v in range(n):
        if par[v] != -1:
            child[par[v]].append(v)
    seq.reverse()
    for v in seq:
        for u in child[v]:
            low[v] = min(low[v], low[u])
    # bridge
    bridge = []
    for p in range(n):
        for c in child[p]:
            if order[p] < low[c]:
                bridge.append((p, c))

    # articulation points
    AP = []
    for v in range(n):
        if v == root:
            if len(child[v]) >= 2:
                AP.append(v)
        else:
            for c in child[v]:
                if order[v] <= low[c]:
                    AP.append(v)
                    break
    return AP, bridge

_, bridge = lowlink(g, 0)
print((len(bridge)))


import sys
sys.setrecursionlimit(10 ** 9)
# input = sys.stdin.readline    ####
def int1(x): return int(x) - 1
def II(): return int(input())
def MI(): return list(map(int, input().split()))
def MI1(): return list(map(int1, input().split()))
def LI(): return list(map(int, input().split()))
def LI1(): return list(map(int1, input().split()))
def LLI(rows_number): return [LI() for _ in range(rows_number)]
def MS(): return input().split()
def LS(): return list(input())
def LLS(rows_number): return [LS() for _ in range(rows_number)]
def printlist(lst, k=' '): print((k.join(list(map(str, lst)))))
INF = float('inf')
# from math import ceil, floor, log2
# from collections import deque, defaultdict
# from itertools import combinations as comb, combinations_with_replacement as comb_w, accumulate, product, permutations
# from heapq import heapify, heappop, heappush
# import numpy as np    # cumsum
# from bisect import bisect_left, bisect_right

"""
https://note.nkmk.me/python-union-find/
素集合データ構造

:parameter
union(x, y): 2つの集合を一つに併合する
find(x): xがどの集合に属しているかを判定する
size(x): 要素xが属するグループのサイズ（要素数）を返す
same(x, y): 要素x, yが同じグループに属するかどうかを返す
members(x): 要素xが属するグループに属する要素をリストで返す
roots(): 全ての根の要素をリストで返す
group_count(): グループの数を返す
all_group_members(): 辞書を返す。　key = ルート要素, value = そのグループに含まれる要素のリスト
__str__(): print()での表示用。ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す
"""
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def all_group_count(self):
        return [self.size(r) for r in self.roots()]

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


def solve():
    N, M = MI()
    E = []
    for i in range(M):
        a, b = MI1()
        E.append((a, b))

    ans = 0
    for a, b in E:
        uf = UnionFind(N)
        for v1, v2 in E:
            if (v1, v2) == (a, b):
                continue
            uf.union(v1, v2)
        # print(uf.group_count())
        if uf.group_count() > 1:
            ans += 1
    print(ans)

def __starting_point():
    solve()


__starting_point()

n, m = list(map(int, input().split()))
adj = [[0]*(n+1) for _ in range(n+1)] #idx; 1~n
edges = [tuple(map(int, input().split())) for _ in range(m)]
cnt = 0

for e in edges:
    x, y = e
    adj[x][y] = 1
    adj[y][x] = 1

def dfs(s):
        seen[s] = 1
        for nx in range(1, n+1):
            if adj[s][nx]:
                if seen[nx]:
                    continue
                dfs(nx)
                
for bridge in edges:
    bx, by = bridge
    adj[bx][by] = 0 #道を除く
    adj[by][bx] = 0
    seen = [0]*(n+1)
    dfs(1) #1から深さ優先探索seenを埋める
    is_ok = 1
    if any(seen[i] == 0 for i in range(1, n+1)):
        is_ok = 0
    if not is_ok:
        cnt += 1
    adj[bx][by] = 1 #道を戻す
    adj[by][bx] = 1

print(cnt)


import queue

n, m = list(map(int, input().split()))
am_bm = []
side_map = dict()
for i in range(m):
    ai, bi = list(map(int, input().split()))
    if ai not in side_map:
        side_map[ai] = set()
        side_map[ai].add(bi)
    else:
        side_map[ai].add(bi)
    if bi not in side_map:
        side_map[bi] = set()
        side_map[bi].add(ai)
    else:
        side_map[bi].add(ai)
    am_bm.append((ai, bi))

counter = 0
for i in range(m):
    a, b = am_bm[i]
    q = queue.Queue()
    q.put(1)
    node_passed = set()
    node_passed.add(1)
    while not q.empty():
        a_tmp = q.get()
        for b_tmp in side_map[a_tmp]:
            if a_tmp == a and b_tmp == b or a_tmp == b and b_tmp == a:
                pass
            elif b_tmp not in node_passed:
                q.put(b_tmp)
                node_passed.add(b_tmp)
    if len(node_passed) == n:
        counter += 1
print((m - counter))


# どの2点間も辺を辿れば到達できる　＝　連結グラフ
# どう頑張ってもたどり着けない　＝　非連結グラフ
N, M = list(map(int, input().split()))
AB = [list(map(int, input().split())) for i in range(M)]


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


# 1辺を省いてUnionFindしたとき、グループ数が２以上になったらその辺は「橋」
ans = 0
for i in range(M):
    u = UnionFind(N)
    for j, ab in enumerate(AB):
        if i == j:
            continue
        else:
            a, b = ab
            u.union(a - 1, b - 1)
    if u.group_count() != 1:
        ans += 1

print(ans)


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].append(b-1)
    edges[b-1].append(a-1)

ind = 1
queue = [0]
visitedOrder = {}
visited = {}
cnt = 0

while queue:
    cur = queue[-1]

    if cur not in visited:
        visited[cur] = ind
        visitedOrder[cur] = ind
        ind += 1

    neighbours = False
    for nei in edges[cur]:
        if nei not in visited:
            neighbours = True
            queue.append(nei)
            break

    if not neighbours:
        queue.pop()

        if cur != 0:
            connected = visited[cur]

            for nei in edges[cur]:
                if nei != queue[-1]:
                    connected = min(connected, visited[nei])

            visited[cur] = connected
            if connected > visitedOrder[queue[-1]]:
                cnt += 1

print(cnt)

def dfs(current):
    for maps in Graph[current]:
        if maps in already:
            continue
        else:
            already.append(maps)
            dfs(maps)

n,m = map(int,input().split())
ans = 0
Edges = []
for _ in range(m):
    Edges.append([int(j)-1 for j in input().split()])

for i in range(m):
    egdes = Edges[0:i]+Edges[i+1:]
    Graph = [[] for _ in range(n)]
    for edge in egdes:
        Graph[edge[0]].append(edge[1])
        Graph[edge[1]].append(edge[0])
    already = []
    dfs(0)
    if len(already) != n:
        ans += 1
print(ans)

import math
from math import gcd,pi,sqrt
INF = float("inf")

import sys
sys.setrecursionlimit(10**6)
import itertools
from collections import Counter,deque
def i_input(): return int(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 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()
    ab = [i_list() for i in range(m)]

    def dfs(table):
        visited = [1]
        que = [1]

        while que != []:
            now = que[0]
            del que[0]

            for index, e in enumerate(table[now]):
                if (e==1) & (index not in visited):
                    visited.append(index)
                    que.append(index)
        if len(visited) == n:
            return 0
        else:
            return 1

    ans = 0
    for i in range(m):
        graph = ab.copy()
        del graph[i]
        table = [[0]*(n+1) for i in range(n+1)]
        for a,b in graph:
            table[a][b] = 1
            table[b][a] = 1

        ans += dfs(table)
    print(ans)



def __starting_point():
    main()

__starting_point()

import networkx as nx

N, M = map(int, input().split())
G = nx.Graph()
G.add_nodes_from(range(1, N + 1))
G.add_edges_from([tuple(map(int, input().split())) for _ in range(M)])

print(len(tuple(nx.bridges(G))))# nx.bridges……橋となる辺をイテレータとして返す

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x,  y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x
    
    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return list(i for i in range(self.n) if self.find(i) == root)

    def roots(self):
        return list(i for i, x in enumerate(self.parents) if x < 0)

    def group_count(self):
        return len(self.roots)

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

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

ans = 0
for i in range(M): # 取り除く辺の番号
    uf = UnionFind(N)
    for j in range(M): # 辺を追加しない（取り除く）
        if i == j:
            continue
        uf.union(*adj[j])
    if len(set(uf.roots())) != 1:
        ans += 1
print(ans)



from collections import defaultdict

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

G = defaultdict(list)

AB = []
for _ in range(M):
    a, b = list(map(int, input().split()))
    a, b = a, b
    G[a].append(b)
    G[b].append(a)
    AB.append((a, b))

# print(f'{G=}')


def f(a, b):
    S = set([])
    Q = [1]
    while True:
        QQ = []
        for q in Q:
            S.add(q)
            for j in G[q]:
                if q == a and j == b:
                    continue
                if q == b and j == a:
                    continue
                if j not in S:
                    QQ.append(j)
        if len(QQ) == 0:
            break
        Q = QQ
        # print(f'{QQ=}')
    # print(f'{a=}, {b=}, {S=}')
    return 1 if len(S) != N else 0


cnt = 0
for a, b in AB:
    cnt += f(a, b)

# print(f'{cnt=}')
print(cnt)


import sys
sys.setrecursionlimit(10**9)
class UnionFind:
  def __init__(self, n):
    self.n = [-1]*n
    self.r = [0]*n
    self.siz = n

  def find_root(self, x):
    if self.n[x] < 0:
      return x
    else:
      self.n[x] = self.find_root(self.n[x])
      return self.n[x]

  def unite(self, x, y):
    x = self.find_root(x)
    y = self.find_root(y)
    if x == y:
      return
    elif self.r[x] > self.r[y]:
      self.n[x] += self.n[y]
      self.n[y] = x
    else:
      self.n[y] += self.n[x]
      self.n[x] = y
      if self.r[x] == self.r[y]:
        self.r[y] += 1
    self.siz -= 1

  def root_same(self, x, y):
    return self.find_root(x) == self.find_root(y)

  def count(self, x):
    return -self.n[self.find_root(x)]

  def size(self):
    return self.siz

n,m=list(map(int,input().split()))
edges=[list(map(int,input().split()))for _ in range(m)]
ans=0
for i in range(m):
  u=UnionFind(n)
  for j in range(m):
    if j==i:continue
    a,b=edges[j]
    a-=1
    b-=1
    u.unite(a,b)
  if u.size()!=1:ans+=1
print(ans)


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


class Union_Find:
    def __init__(self, n):
        self.par = [-1] * n
        self.siz = [1] * n

    def root(self, x):
        if self.par[x] == -1:
            return x
        else:
            return self.root(self.par[x])

    def issame(self, x, y):
        return self.root(x) == self.root(y)

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)

        if x == y:
            return False

        if self.siz[x] < self.siz[y]:
            tmp = x
            x = y
            y = tmp

        self.par[y] = x
        self.siz[x] += self.siz[y]
        return True

    def size(self, x):
        return self.siz[x]


ans = 0
for m in range(M):
    uf = Union_Find(N)
    for i in range(M):
        if i == m:
            continue
        
        a, b = AB[i]
        a -= 1
        b -= 1
        uf.unite(a, b)

    ans += len(set([uf.root(x) for x in range(N)])) != 1

print(ans)

class UnionFind():
  def __init__(self, n):
    self.n = n
    self.parent = [i for i in range(self.n)]
    self.rank = [0] * self.n
  
  def find_root(self, x):
    if self.parent[x] == x:
      return x
    else:
      self.parent[x] = self.find_root(self.parent[x])
      return self.parent[x]
  
  def unite(self, x, y):
    rx = self.find_root(x)
    ry = self.find_root(y)
    if rx == ry:
      return
    if self.rank[rx] < self.rank[ry]:
      self.parent[rx] = ry
    else:
      self.parent[ry] = rx
      if self.rank[rx] == self.rank[ry]:
        self.rank[rx] += 1
  
  def is_same(self, x, y):
    return self.find_root(x) == self.find_root(y)

N, M = map(int, input().split())
edge = []
bridge = 0
for _ in range(M):
  e = list(map(lambda x: int(x)-1, input().split()))
  edge.append(e)

for i in range(M):
  uf = UnionFind(N)
  for j in range(M):
    if j == i:
      continue
    uf.unite(edge[j][0], edge[j][1])
  
  root = uf.find_root(0)
  for i in range(1, N):
    if root != uf.find_root(i):
      bridge += 1
      break

print(bridge)

from sys import stdin
nii=lambda:map(int,stdin.readline().split())
lnii=lambda:list(map(int,stdin.readline().split()))
from collections import deque
from copy import deepcopy

n,m=nii()
l=[lnii() for i in range(m)]

def BFS(t_l):
  tree=[[] for i in range(n)]
  for a,b in t_l:
    a-=1
    b-=1
    tree[a].append(b)
    tree[b].append(a)

  dist=[-1 for i in range(n)]
  dist[0]=0

  que=deque()
  que.append(0)

  while que:
    x=que.popleft()
    for i in tree[x]:
      if dist[i]==-1:
        que.append(i)
        dist[i]=dist[x]+1

  return dist

ans=0
for i in range(m):
  t_l=deepcopy(l)
  del t_l[i]
  dist=BFS(t_l)
  if -1 in dist:
    ans+=1

print(ans)

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

def solve(e):
    parent=[i for i in range(N)]
    def find(x,parent):
        y=parent[x]
        while y!=parent[y]:
            y=find(y,parent)
        parent[x]=y
        return y
    def unite(a,b,parent):
        x=find(a,parent)
        y=find(b,parent)
        if x!=y:
            parent[x]=y

    for i in range(M):
        if i==e:
            continue
        unite(a[i],b[i],parent)
    cnt=[0 for _ in range(N)]
    for i in range(N):
        cnt[find(i,parent)]=1
    if cnt.count(1)>1:
        return 1
    else:
        return 0
ans=0
for i in range(M):
    ans+=solve(i)
print(ans)


import sys
from collections import deque

input = sys.stdin.readline
N, M = map(int, input().split())

edges = [[] for _ in range(N)]
edge_set = set()
for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    edges[a].append(b)
    edges[b].append(a)

    edge_set.add((a, b))

ans = 0
for a, b in edge_set:
    q = deque()
    q.append(0)
    visited = set()
    while q:
        p = q.popleft()
        if p in visited:
            continue
        visited.add(p)
        for np in edges[p]:
            if (p, np) == (a, b) or (np, p) == (a, b):
                continue
            q.append(np)
    if len(visited) != N:
        ans += 1

print(ans)

import sys
readline = sys.stdin.readline

N,M = map(int,readline().split())
bridges = [None] * M
G = [[] for i in range(N)]

for i in range(M):
  a,b = map(int,readline().split())
  G[a - 1].append(b - 1)
  G[b - 1].append(a - 1)
  bridges[i] = (a - 1, b - 1)
  
from collections import deque

ans = 0
for i in range(M):
  q = deque([])
  q.append(0)
  seen = set()
  while q:
    v = q.popleft()
    if v in seen:
      continue
    seen.add(v)
    for child in G[v]:
      if (v, child) == bridges[i] or (child, v) == bridges[i]:
        continue
      q.append(child)
  if len(seen) != N:
    ans += 1
    
print(ans)

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

N,M = list(map(int,input().split()))
edges = []
for i in range(M):
    x = list(map(int,input().split()))
    edges.append(x)
ans = 0
for i in range(M):
    uf = UnionFind(N)
    for j in range(M):
        if j != i:
            uf.union(edges[j][0]-1,edges[j][1]-1)
        if j == M-1 and uf.group_count() != 1:
            ans += 1
print(ans)


n,m = map(int,input().split())
par = [i for i in range(n+1)]
def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x]) #経路圧縮
        return par[x]
def same(x,y):
    return find(x) == find(y)
def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
ls = [list(map(int,input().split())) for _ in range(m)]
ans = 0
for i in ls:
    for k in ls:
        if i != k:
            [a,b] = k
            unite(a,b)
    flag = True
    for p in range(1,n+1):
        for q in range(1,n+1):
            if not same(p,q):
                flag = False
                break
        if flag == False:
            break
    if flag == False:
        ans += 1
    par = [i for i in range(n+1)]
print(ans)