Problem:
 Score : 300 points    Problem Statement 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 1 7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7      Sample Output 1 4  The figure below shows the given graph:     The edges shown in red are bridges. There are four of them.       Sample Input 2 3 3
1 2
1 3
2 3      Sample Output 2 0  It is possible that there is no bridge.       Sample Input 3 6 5
1 2
2 3
3 4
4 5
5 6      Sample Output 3 5  It is possible that every edge is a bridge.

Solution (Python):

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
from operator import itemgetter
def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print('\n'.join(x))
def printni(x): print('\n'.join(list(map(str,x))))
inf = 10**17
mod = 10**9 + 7

def dfs(x,tree,al):
    for i in tree[x]:
        if al[i]<0:
            al[i]=0
            dfs(i,tree,al)
    
        
def main():  
    n,m=MI()
    lis=[LI() for i in range(m)]
    
    cou=0
    for i in range(m):
        tree=[[] for i in range(n)]
        for j in range(m):
            if i!=j:
                tree[lis[j][0]-1].append(lis[j][1]-1)
                tree[lis[j][1]-1].append(lis[j][0]-1)
        count=0
        for k in range(n):
            al=[-1]*n
            al[k]=0
            dfs(k,tree,al)
            
            if not -1 in al:
                count+=1
        if count!=n:
            cou+=1
    print(cou)    

if __name__ == '__main__':
    main()

Solution (Python):

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
from operator import itemgetter
def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print('\n'.join(x))
def printni(x): print('\n'.join(list(map(str,x))))
inf = 10**17
mod = 10**9 + 7

def dfs(x):
    for i in tree[x]:
        if al[i]<0:
            al[i]=0
            dfs(i)
    
        
    
n,m=MI()
lis=[LI() for i in range(m)]

cou=0
for i in range(m):
    tree=[[] for i in range(n)]
    for j in range(m):
        if i!=j:
            tree[lis[j][0]-1].append(lis[j][1]-1)
            tree[lis[j][1]-1].append(lis[j][0]-1)
    count=0
    for k in range(n):
        al=[-1]*n
        al[k]=0
        dfs(k)
        
        if not -1 in al:
            count+=1
    if count!=n:
        cou+=1
print(cou)

Solution (Python):

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
from operator import itemgetter
def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print('\n'.join(x))
def printni(x): print('\n'.join(list(map(str,x))))
inf = 10**17
mod = 10**9 + 7

def dfs(x):
    for i in tree[x]:
        if al[i]<0:
            al[i]=0
            dfs(i)
    
        
    
n,m=MI()
lis=[LI() for i in range(m)]

cou=0
for i in range(m):
    tree=[[] for i in range(n)]
    for j in range(m):
        if i!=j:
            tree[lis[j][0]-1].append(lis[j][1]-1)
            tree[lis[j][1]-1].append(lis[j][0]-1)
    count=0
    for k in range(n):
        al=[-1]*n
        al[k]=0
        dfs(k)
        
        if not -1 in al:
            count+=1
    if count!=n:
        cou+=1
print(cou)

Solution (Python):

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
from operator import itemgetter
def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print('\n'.join(x))
def printni(x): print('\n'.join(list(map(str,x))))
inf = 10**17
mod = 10**9 + 7

def dfs(x):
    for i in tree[x]:
        if al[i]<0:
            al[i]=0
            dfs(i)
    
        
    
n,m=MI()
lis=[LI() for i in range(m)]

cou=0
for i in range(m):
    tree=[[] for i in range(n)]
    for j in range(m):
        if i!=j:
            tree[lis[j][0]-1].append(lis[j][1]-1)
            tree[lis[j][1]-1].append(lis[j][0]-1)
    count=0
    for k in range(n):
        al=[-1]*n
        al[k]=0
        dfs(k)
        
        if sum(al)==0:
            count+=1
    if count!=n:
        cou+=1
print(cou)

Solution (Python):
N, M = map(int, input().split())
ls = [tuple(map(lambda x: int(x) - 1, input().split())) for _ in range(M)]


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

def unite(par, rank, x, y):
    rx = find(par, x)
    ry = find(par, y)

    if rx == ry:
        return False
    else:
        if rank[rx] < rank[ry]:
            par[rx] = ry
        else:
            par[ry] = rx
            if rank[rx] == rank[ry]: rank[rx] += 1
        return True

def same(par, x, y):
    return find(par, x) == find(par, y)

c = 0
for i in range(M):
    par = [-1] * N
    rank = [0] * N
    for idx, (a, b) in enumerate(ls):
        if idx == i:
            continue
        unite(par, rank, a, b)
    
    
    if len([i for i, x in enumerate(par) if x < 0]) >= 2:
        c += 1
print(c)

Solution (Python):






import sys
input = sys.stdin.readline

import math

import bisect
from collections import defaultdict
from collections import deque
from functools import lru_cache






MOD = 10**9+7
INF = float('inf')






def I(): return int(input().strip())
def S(): return input().strip()
def IL(): return list(map(int,input().split()))
def SL(): return list(map(str,input().split()))
def ILs(n): return list(int(input()) for _ in range(n))
def SLs(n): return list(input().strip() for _ in range(n))
def ILL(n): return [list(map(int, input().split())) for _ in range(n)]
def SLL(n): return [list(map(str, input().split())) for _ in range(n)]


def P(arg): print(arg); return
def Y(): print("Yes"); return
def N(): print("No"); return
def E(): exit()
def PE(arg): print(arg); exit()
def YE(): print("Yes"); exit()
def NE(): print("No"); exit()


def DD(arg): return defaultdict(arg)



def inv(n): return pow(n, MOD-2, MOD)


kaijo_memo = []
def kaijo(n):
  if(len(kaijo_memo) > n):
    return kaijo_memo[n]
  if(len(kaijo_memo) == 0):
    kaijo_memo.append(1)
  while(len(kaijo_memo) <= n):
    kaijo_memo.append(kaijo_memo[-1] * len(kaijo_memo) % MOD)
  return kaijo_memo[n]

gyaku_kaijo_memo = []
def gyaku_kaijo(n):
  if(len(gyaku_kaijo_memo) > n):
    return gyaku_kaijo_memo[n]
  if(len(gyaku_kaijo_memo) == 0):
    gyaku_kaijo_memo.append(1)
  while(len(gyaku_kaijo_memo) <= n):
    gyaku_kaijo_memo.append(gyaku_kaijo_memo[-1] * pow(len(gyaku_kaijo_memo),MOD-2,MOD) % MOD)
  return gyaku_kaijo_memo[n]

def nCr(n,r):
  if(n == r):
    return 1
  if(n < r or r < 0):
    return 0
  ret = 1
  ret = ret * kaijo(n) % MOD
  ret = ret * gyaku_kaijo(r) % MOD
  ret = ret * gyaku_kaijo(n-r) % MOD
  return ret


def factorization(n):
  arr = []
  temp = n
  for i in range(2, int(-(-n**0.5//1))+1):
    if temp%i==0:
      cnt=0
      while temp%i==0: 
        cnt+=1 
        temp //= i
      arr.append([i, cnt])
  if temp!=1:
    arr.append([temp, 1])
  if arr==[]:
    arr.append([n, 1])
  return arr


def make_divisors(n):
  divisors = []
  for i in range(1, int(n**0.5)+1):
    if n % i == 0:
      divisors.append(i)
      if i != n // i: 
        divisors.append(n//i)
  return divisors


def gcd(a, b):
    while b:
        a, b = b, a % b
    return a


def lcm(a, b):
    return a * b // gcd (a, b)


def count_bit(n):
  count = 0
  while n:
    n &= n -1
    count += 1
  return count


def base_10_to_n(X, n):
  if X//n:
    return base_10_to_n(X//n, n)+[X%n]
  return [X%n]

def base_n_to_10(X, n):
  return sum(int(str(X)[-i-1])*n**i for i in range(len(str(X))))


def int_log(n, a):
  count = 0
  while n>=a:
    n //= a
    count += 1
  return count





N,M = IL()
data = ILL(M)


ans = 0
for i in range(M):
  graph = [[] for i in range(N)]
  for j in range(M):
    if i != j:
      a,b = data[j]
      graph[a-1].append(b-1)
      graph[b-1].append(a-1)
  d = [0 for i in range(N)]
  q = [0]
  d[0] = 1
  while q:
    u = q.pop()
    for v in graph[u]:
      if d[v] != 1:
        d[v] = 1
        q.append(v)
  if 0 in d:
    ans += 1
print(ans)

Solution (Python):

import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
from operator import itemgetter
def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print('\n'.join(x))
def printni(x): print('\n'.join(list(map(str,x))))
inf = 10**17
mod = 10**9 + 7

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=MI()
edge=[]
for i in range(m):
    edge.append(LI())
u=UnionFind(n)
count=0
for i in range(m):
    u=UnionFind(n)
    for j in range(m):
        if i==j:
            continue
        else:
            u.union(edge[j][0]-1,edge[j][1]-1)
    if u.group_count()>1:
        count+=1
print(count)

Solution (Python):
from collections import defaultdict


def main():
    N, M = list(map(int, input().split(' ')))
    adj_nodes = defaultdict(list)
    edges = list()
    for _ in range(M):
        a, b = list(map(int, input().split(' ')))
        a -= 1
        b -= 1
        edges.append((a, b))
        adj_nodes[a].append(b)
        adj_nodes[b].append(a)
    ans = 0
    for removed_edge in edges:
        a, b = removed_edge
        visited = [0 for _ in range(N)]
        frontier = [0]
        
        while len(frontier) > 0:
            node = frontier.pop()
            visited[node] = 1
            for next_node in adj_nodes[node]:
                if visited[next_node] == 1:
                    continue
                if (node, next_node) in [(a, b), (b, a)]:
                    continue
                frontier.append(next_node)
        if min(visited) == 0:
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
from collections import deque
n, m = map(int, input().split())
ab = []
for _ in range(m):
    a, b = map(int, input().split())
    ab.append((a-1, b-1))
ans = 0
for i in range(m):
    graph = [[] for _ in range(n)]
    for j in range(m):
        if i==j:
            continue
        a, b = ab[j]
        graph[a].append(b)
        graph[b].append(a)
    q = deque([0])
    seen = [False]*n
    seen[0] = True
    while q:
        node = q.popleft()
        for child in graph[node]:
            if seen[child]:
                continue
            seen[child] = True
            q.append(child)
    if not all(seen):
        ans += 1
print(ans)

Solution (Python):
N, M = map(int, input().split())
AB = []
ans = 0

for _ in range(M):
    Ai, Bi = map(int, input().split())
    AB.append((Ai,Bi))

for i in range(M):
    memo = [[] for _ in range(N+1)]
    for j in range(M):
        if i != j:
            memo[AB[j][0]].append(AB[j][1])
            memo[AB[j][1]].append(AB[j][0])
    queue = [1]
    visited = [0] * (N+1)

    while queue:
        node = queue.pop()
        next_nodes = memo[node]
        for next_node in next_nodes:
            if visited[next_node] == 0:
                queue.append(next_node)
        visited[node] = 1

    if sum(visited[1:]) != N:
        ans += 1

print(ans)

Solution (Python):
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())
e=[]
ans=0

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

Solution (Python):
from collections import deque
from copy import deepcopy

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

def DFS(m):
  t_l=deepcopy(l)
  del t_l[m]

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

  seen=set()
  seen.add(0)

  dq=deque()
  dq.append(0)

  while dq:
    x=dq.pop()
    for i in tree[x]:
      if i not in seen:
        dq.append(i)
        seen.add(i)

  return seen

ans=0
for i in range(m):
  st=DFS(i)
  if len(st)!=n:
    ans+=1

print(ans)

Solution (Python):
from collections import deque
from copy import deepcopy

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

def BFS(m):
  t_l=deepcopy(l)
  del t_l[m]

  tree=[[] for j 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

  global ans
  if -1 in dist:
    ans+=1

ans=0
for i in range(m):
  BFS(i)

print(ans)

Solution (Python):
from collections import deque
from copy import deepcopy

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

def BFS(m):
  t_l=deepcopy(l)
  del t_l[m]

  tree=[[] for j 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):
  d=BFS(i)
  if -1 in d:
    ans+=1

print(ans)

Solution (Python):
def main():
    n, m = map(int, input().split())
    array = [[] for _ in range(n+1)]
    temp = []
    for _ in range(m):
        a, b = map(int, input().split())
        array[a].append(b)
        array[b].append(a)
        temp.append([a, b])
    result = 0
    from collections import deque
    while len(temp) > 0:
        a, b = temp.pop()
        array[a].remove(b)
        array[b].remove(a)
        d = deque([1])
        pop = d.pop
        append = d.append
        flag = [True] * (n + 1)
        while len(d) > 0:
            now = pop()
            for to in array[now]:
                if flag[to]:
                    append(to)
                    flag[to] = False
        for f in flag[1:]:
            if f:
                result += 1
                break
        array[a].append(b)
        array[b].append(a)
    print(result)
main()

Solution (Python):
def main():
    n, m = map(int, input().split())
    array = [[] for _ in range(n+1)]
    temp = []
    for _ in range(m):
        a, b = map(int, input().split())
        array[a].append(b)
        array[b].append(a)
        temp.append([a, b])
    result = 0
    from collections import deque
    while len(temp) > 0:
        a, b = temp.pop()
        array[a].remove(b)
        array[b].remove(a)
        d = deque([1])
        pop = d.popleft
        append = d.append
        flag = [True] * (n + 1)
        while len(d) > 0:
            now = pop()
            for to in array[now]:
                if flag[to]:
                    append(to)
                    flag[to] = False
        for f in flag[1:]:
            if f:
                result += 1
                break
        array[a].append(b)
        array[b].append(a)
    print(result)
main()

Solution (Python):
import numpy as np
from scipy.sparse.csgraph import connected_components
from collections import deque
n,m=map(int,input().split())
matrix=[[0]*n]*n
matrix=np.array(matrix)
l=deque()
for _ in range(m):
    a,b=map(int,input().split())
    l.append([a,b])
    matrix[a-1][b-1]=1
count=0
for i in range(m):
    [a,b]=l.popleft()
    matrix[a-1][b-1]=0
    k,kk=connected_components(matrix)
    if kk[a-1]!=kk[b-1]:
        count+=1
    l.append([a,b])
    matrix[a-1][b-1]=1
print(count)

Solution (Python):
from collections import deque

def check(st,en,ed):
    ed[st-1][en-1] -= 1
    ed[en-1][st-1] -= 1
    cnt = [0] * n
    q = deque()
    q.append(st)
    cnt[st-1] += 1
    while q:
        now = q.popleft()
        if ed[now-1][en-1] == 1:
            ed[st-1][en-1] += 1
            ed[en-1][st-1] += 1
            return False
        for r in range(n):
            if ed[now-1][r] == 1 and cnt[r] == 0:
                q.append(r+1)
                cnt[r] += 1
    ed[st-1][en-1] += 1
    ed[en-1][st-1] += 1
    return True

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

edge = [[0] * n for _ in range(n)] 

nodes = []

for i in range(m):
    a, b = map(int, input().split())
    nodes.append((a,b))
    edge[a-1][b-1] += 1
    edge[b-1][a-1] += 1

ans = 0 
for node in nodes:
    a,b = node[0], node[1]
    if check(a,b,edge):
        ans += 1

print(ans)

Solution (Python):
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60


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, *AB = map(int, read().split())
A = AB[::2]
B = AB[1::2]

ans = 0
for i in range(M):
    uf = UnionFind(N)
    for j, (a, b) in enumerate(zip(A, B)):
        if i != j:
            uf.union(a - 1, b - 1)
    if uf.group_count() > 1:
        ans += 1

print(ans)

Solution (Python):
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60


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, *AB = map(int, read().split())
A = AB[::2]
B = AB[1::2]

ans = 0
for i in range(M):
    uf = UnionFind(N)
    for j, (a, b) in enumerate(zip(A, B)):
        if i != j:
            uf.union(a - 1, b - 1)
    if uf.group_count() > 1:
        ans += 1

print(ans)

Solution (Python):
import numpy as np
from scipy.sparse.csgraph import connected_components
from collections import deque
n,m=map(int,input().split())
matrix=[[0]*n]*n
matrix=np.array(matrix)
l=deque()
for _ in range(m):
    a,b=map(int,input().split())
    l.append([a,b])
    matrix[a-1][b-1]=1
count=0
for i in range(m):
    [a,b]=l.popleft()
    matrix[a-1][b-1]=0
    k,kk=connected_components(matrix)
    if kk[a-1]!=kk[b-1]:
        count+=1
    l.append([a,b])
    matrix[a-1][b-1]=1
print(count)

Solution (Python):
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())
graph = [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(graph[j][0]-1, graph[j][1]-1)
    if uf.group_count() != 1:
        ans += 1
print(ans)

Solution (Python):
from collections import deque


def bfs(NEAR, S, N):  
    frag = set([S])
    que = deque([S])

    while len(que) > 0:
        q = que.popleft()
        for i in NEAR[q]:
            if i not in frag:
                que.append(i)
                frag.add(i)

    ans = 1
    if len(frag) == N:
        ans = 0
    return ans


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

near = [set([]) for _ in range(n)]
for i, j in ab:
    near[i - 1].add(j - 1)
    near[j - 1].add(i - 1)

cnt = 0
for i, j in ab:
    near[i - 1].remove(j - 1)
    near[j - 1].remove(i - 1)
    cnt += bfs(near,1,n)
    near[i - 1].add(j - 1)
    near[j - 1].add(i - 1)
print(cnt)

Solution (Python):
from collections import deque


def bfs(NEAR, S, N):  
    dist = [-1 for _ in range(N)]
    pas = [-1 for _ in range(N)]
    dist[S], pas[S] = 0, 's'
    frag = set([S])
    que = deque([S])

    while len(que) > 0:
        q = que.popleft()
        near = NEAR[q]
        for i in near:
            if i in frag:
                continue
            que.append(i)
            frag.add(i)

    ans = 1
    if len(frag) == N:
        ans = 0
    return ans


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

near = [set([]) for _ in range(n)]
for i, j in ab:
    near[i - 1].add(j - 1)
    near[j - 1].add(i - 1)

cnt = 0
for i, j in ab:
    near[i - 1].remove(j - 1)
    near[j - 1].remove(i - 1)
    cnt += bfs(near,1,n)
    near[i - 1].add(j - 1)
    near[j - 1].add(i - 1)
print(cnt)

Solution (Python):













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())


def main():
    N, M = map(int, input().split())

    a = [0] * M
    b = [0] * M
    for i in range(M):
        a[i], b[i] = map(int, input().split())

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

    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
import sys
read = sys.stdin.buffer.read
input = sys.stdin.readline
input = sys.stdin.buffer.readline





def RD(): return sys.stdin.read()
def II(): return int(input())
def MI(): return map(int,input().split())
def MF(): return map(float,input().split())
def LI(): return list(map(int,input().split()))
def LF(): return list(map(float,input().split()))
def TI(): return tuple(map(int,input().split()))





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())



def main():
	n,m=MI()
	li=[]
	for _ in range(m):
		a,b=MI()
		a-=1
		b-=1
		li.append([a,b])
	

	ans=0

	for i in range(m):
		UF=UnionFind(n)
		for j in range(m):
			if i==j:
				continue
			UF.union(li[j][0],li[j][1])
		ans+=(UF.group_count()==1)
	print(m-ans)


if __name__ == "__main__":
	main()