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):
def search(u, g, visited):
	if visited[u]:
		return
	visited[u] = True
	for v in g[u]:
		search(v, g, visited)

def resolve():
	n, m = map(int, input().split())
	edges = [list(map(int, input().split())) for _ in range(m)]
	ans = 0
	for i in range(m):
		g = [[] for _ in range(n)]
		for j in range(m):
			if i == j:
				continue
			a, b = edges[j]
			g[a-1].append(b-1)
			g[b-1].append(a-1)
		visited = [False]*n
		search(0, g, visited)
		if visited.count(True) != n:
			ans += 1
	print(ans)
resolve()

Solution (Python):
import networkx as nx

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

print(len(tuple(nx.bridges(G))))

Solution (Python):

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

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

cnt=0

for x in ab:
  ls=list(range(n))
  for y in ab:
    if y !=x:
      for i in range(n):
        ls=[ls[y[0]-1] if ls[i]==ls[y[1]-1] else ls[i] for i in range(n)] 
  if len(set(ls)) !=1:
    cnt+=1

print(cnt)

Solution (Python):
def main():
    n, m = map(int, input().split())
    e = [set() for _ in range(n)]
    for _ in range(m):
        u, v = map(lambda x: int(x) - 1, input().split())
        e[u].add(v)
        e[v].add(u)

    ans = 0
    for _ in range(m):
        count = 0
        for i, x in enumerate(e):
            if len(x) == 1:
                j = x.pop()
                e[j] -= {i}
                count += 1
        if count:
            ans += count
        else:
            print(ans)
            exit()


if __name__ == "__main__":
    main()

Solution (Python):
def main():
    n, m, *ab = map(int, open(0).read().split())
    e = [set() for _ in range(n)]
    for u, v in zip(*[iter(ab)] * 2):
        e[u - 1].add(v - 1)
        e[v - 1].add(u - 1)

    ans = 0
    for _ in range(m):
        count = 0
        for i, x in enumerate(e):
            if len(x) == 1:
                j = x.pop()
                e[j] -= {i}
                count += 1
        if count:
            ans += count
        else:
            print(ans)
            exit()


if __name__ == "__main__":
    main()

Solution (Python):
def main():
    n, m, *ab = map(int, open(0).read().split())
    e = [[] for _ in range(n)]
    for u, v in zip(*[iter(ab)] * 2):
        e[u - 1].append(v - 1)
        e[v - 1].append(u - 1)

    ans = 0
    for _ in range(m):
        count = 0
        for i, x in enumerate(e):
            if len(x) == 1:
                e[i] = []
                e[x[0]].remove(i)
                count += 1
        if count:
            ans += count
        else:
            print(ans)
            exit()




if __name__ == "__main__":
    main()

Solution (Python):
def main():
    n, m, *ab = map(int, open(0).read().split())
    e = [[] for _ in range(n)]
    for u, v in zip(*[iter(ab)] * 2):
        e[u - 1].append(v - 1)
        e[v - 1].append(u - 1)

    ans = 0
    for _ in range(m):
        count = 0
        for i, x in enumerate(e):
            if len(x) == 1:
                e[i] = []
                e[x[0]].remove(i)
                count += 1
        if count:
            ans += count
        else:
            break

    print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
import copy


def main():
    
    
    n, w = map(int, input().split())
    
    d = [[False] * n for i in range(n)]

    
    e = []
    for i in range(w):
        
        u, v = map(lambda x: int(x) - 1, input().split())
        e.append([u, v])
        
        d[u][v] = True
        d[v][u] = True

    def dfs(graph, visited, x):
        if visited[x]:
            return
        visited[x] = True
        for i in range(n):
            if graph[x][i]:
                dfs(graph, visited, i)

    ans = 0
    for (u, v) in e:
        graph = copy.deepcopy(d)
        graph[u][v] = False
        graph[v][u] = False
        for i in range(n):
            visited = [False for _ in range(n)]
            dfs(graph, visited, i)
            if not all(visited):
                ans += 1
                break
    print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
import numpy as np
import sys ; sys.setrecursionlimit(2000)
import copy

def dfs(v1):
    visited[v1] = 1
    for v2 in range(n):
        if graph[v1][v2] == 0: continue
        if visited[v2] == 1: continue
        dfs(v2)

n, m = map(int,input().split())
ab = np.array([list(map(int,input().split())) for i in range(m)])
a,b = ab.T[0]-1,ab.T[1]-1


G = np.array([[0] * n for _ in range(n)])
for aa,bb in zip(a,b): G[aa][bb],G[bb][aa] = 1,1

ans = 0
for aa,bb in zip(a,b):
    graph = copy.deepcopy(G)
    graph[aa][bb],graph[bb][aa] = 0,0
    visited = [0]*(n)
    dfs(0)
    if not all(visited): ans += 1

print(ans)

Solution (Python):
class UnionFind():
    
    
    
    def __init__(self, n):
        self.n = n
        
        
        
        self.root = [-1]*(n+1)
        
        
        self.rnk = [0]*(n+1)

    
    
    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.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x

        
        
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1

    
    
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    
    def Count(self, x):
        return -self.root[self.Find_Root(x)]

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())
cnt=0

for i in range(M):
  UN=UnionFind(N)
  for j in range(M):
    if j==i:
      pass
    else:
      UN.Unite(a[j],b[j])
  if UN.isSameGroup(a[i], b[i])==False:
    cnt +=1
    
print(cnt)

Solution (Python):

import sys


class UnionFind():
    def __init__(self, n):
        self.parents = list(range(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:
            self.parents[y] = x


def main():
    N, M = map(int, input().split())
    a = [None] * M
    b = [None] * 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:
                uf.union(a[j]-1, b[j]-1)

        p = uf.find(0)
        for k in range(1, N):
            if p != uf.find(k):
                ans += 1
                break
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
import numpy as np



def find(a):
    if a==root[a]: return a
    else: root[a] = find(root[a]) ; return root[a]
    
def unite(a,b):
    ra,rb = find(a),find(b)
    if ra==rb : return
    else: root[ra] = rb
    
def same(a,b): return find(a)==find(b)

n,m =  map(int,input().split())
ab = np.array([list(map(int,input().split())) for i in range(m)])
a,b = ab.T[0]-1, ab.T[1]-1

ans = 0
for i in range(m):
    root = list(range(n))
    connect = 0
    for j in range(m):
        if i==j: continue
        if not same(a[j],b[j]): unite(a[j],b[j]); connect += 1
    ans += 0 if connect==n-1 else 1
    
print(ans)

Solution (Python):
import numpy as np

def find(x):
    if x == root[x]: return x
    else: root[x] = find(root[x]); return root[x]
def unite(x,y):
    px,py = find(x),find(y)
    if px == py : return
    else: root[px] = py
def same(x,y): return find(x)==find(y)


n,m = map(int,input().split())
ab = np.array([list(map(int,input().split())) for i in range(m)])
a,b = ab.T[0] -1, ab.T[1] -1

ans = 0
for i in range(m): 
    connect = 0
    root = list(range(n))
    for j in range(m): 
        if i != j and  not same(a[j],b[j]):
            unite(a[j],b[j]) ; connect += 1
    ans += 0 if connect == n-1 else 1
print(ans)

Solution (Python):
import numpy as np

class unionfind: 
    def __init__(self,n): 
        self.parent = list(range(n))
    def find(self,a): 
        if self.parent[a] == a: return a 
        else:
            self.parent[a] = self.find(self.parent[a]) 
            return self.parent[a]
    def unite(self,a,b): 
        pa,pb = self.find(a),self.find(b)
        if pa == pb: return 0 
        else: self.parent[pa] = pb
    def same(self,a,b):
        pa,pb = self.find(a),self.find(b)
        return pa == pb


def find(x):
    if node[x] == x: return x
    else: node[x] = find(node[x]) ; return node[x]
def unite(x,y):
    x,y = find(x),find(y)
    if x == y : return
    else: node[x] = y
def same(x,y): return find(x) == find(y)


n,m = map(int,input().split())
ab = np.array([list(map(int,input().split())) for i in range(m)])
a,b = ab.T[0] -1, ab.T[1] -1

ans = 0
for i in range(m): 
    connect = 0
    node = list(range(n))
    for j in range(m): 
        if i != j and  not same(a[j],b[j]): unite(a[j],b[j]) ; connect += 1
    ans += 0 if connect == n-1 else 1
print(ans)

Solution (Python):
import numpy as np

class unionfind: 
    def __init__(self,n): 
        self.parent = list(range(n))
    def find(self,a): 
        if self.parent[a] == a: return a 
        p = self.find(self.parent[a])
        self.parent[a] = p 
        return p
    def unite(self,a,b): 
        pa,pb = self.find(a),self.find(b)
        if pa == pb: return 0 
        self.parent[pa] = pb
    def same(self,a,b):
        pa,pb = self.find(a),self.find(b)
        return pa == pb

n,m = map(int,input().split())
ab = np.array([list(map(int,input().split())) for i in range(m)])
a,b = ab.T[0] -1, ab.T[1] -1

ans = 0
for i in range(m): 
    uf = unionfind(n)
    connect = 0
    for j in range(m): 
        if i != j and not uf.same(a[j],b[j]): uf.unite(a[j],b[j]) ; connect += 1
    ans += 0 if connect == n-1 else 1
print(ans)

Solution (Python):
import sys
import math
import numpy as np
import copy


class unionfind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
        self.groupnum = n

    def unite(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb:
            return
        self.parent[pa] = pb
        
        
        
        
        
        
        self.groupnum -= 1

    def same(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        return pa == pb

    def find(self, a):
        if self.parent[a] == a:
            return a
        p = self.find(self.parent[a])
        self.parent[a] = p
        return p
    


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

    edge_list = []

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

    cnt = 0
    
    for i in range(m):
        uf = unionfind(n)
        for j in range(m):
            if i == j:
                continue
            uf.unite(edge_list[j][0], edge_list[j][1])
        if uf.groupnum >= 2:
            cnt += 1


    print(cnt)
    return 0

if __name__ == '__main__':
    sys.exit(main())

Solution (Python):
import sys
import math
import numpy as np
import copy


class unionfind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
        self.groupnum = n

    def unite(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb:
            return
        if(self.rank[pa] < self.rank[pb]):
            self.parent[pa] = pb
        else:
            self.parent[pb] = pa
            if self.rank[pa] == self.rank[pb]:
                self.rank[pa] += 1
        self.groupnum -= 1

    def same(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        return pa == pb

    def find(self, a):
        if self.parent[a] == a:
            return a
        p = self.find(self.parent[a])
        self.parent[a] = p
        return p
    


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

    edge_list = []

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

    cnt = 0
    
    for i in range(m):
        uf = unionfind(n)
        for j in range(m):
            if i == j:
                continue
            uf.unite(edge_list[j][0], edge_list[j][1])
        if uf.groupnum >= 2:
            cnt += 1


    print(cnt)
    return 0

if __name__ == '__main__':
    sys.exit(main())

Solution (Python):


from pprint import pprint
from collections import deque, defaultdict
import itertools
import math
import sys

sys.setrecursionlimit(10 ** 6)
input = sys.stdin.buffer.readline
INF = float('inf')

n_nodes, m_edges = map(int, input().split())
edges = []
for _ in range(m_edges):
    u, v = map(int, input().split())
    edges.append([u - 1, v - 1])



def find_root(v):
    if v != parents[v]:
        parents[v] = find_root(parents[v])
    return parents[v]


def has_same_root(u, v):
    return find_root(u) == find_root(v)


def unite(u, v):
    root_u, root_v = find_root(u), find_root(v)
    if root_u == root_v:
        return
    if rank[root_u] < rank[root_v]:
        root_u, root_v = root_v, root_u
    parents[root_v] = root_u
    rank[root_u] += rank[root_v]


res = 0
for i in range(m_edges):
    parents = [i for i in range(n_nodes)]
    rank = [1] * n_nodes
    for j in range(m_edges):
        if i == j:
            continue
        u, v = edges[j]
        if not has_same_root(u, v):
            unite(u, v)
    
    count = 0
    for v in range(n_nodes):
        if parents[v] == v:
            count += 1
    if count > 1:
        res += 1

print(res)

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

edges = {}
node_count = 0
node_seen = set()
edge_list = []

def dfs(t_node, t_edge):
    global node_count, node_seen
    node_count += 1
    node_seen.add(t_node)
    next_nodes = set(edges[t_node]) - node_seen
    if len(next_nodes) == 0:
        return
    else:
        for nextn in next_nodes:
            if t_node in t_edge and nextn in t_edge:
                pass
            else:
                dfs(nextn, t_edge)

def main():
    global edges, node_count, node_seen, edge_list
    n, m = map(int, input().split())
    all_nodes = set([i for i in range(1, n + 1)])
    edges = {e: [] for e in range(1, n + 1)}
    for _ in range(m):
        s, g = map(int, input().split())
        edges[s].append(g)
        edges[g].append(s)
        edge_list.append((s, g))
    
    r = 0
    for itry in range(m):
        node_seen = set()
        node_count = 0
        dfs(edge_list[itry][0], edge_list[itry])
        r += all_nodes != node_seen

    print(r)

if __name__ == '__main__':
    main()

Solution (Python):
from collections import deque
n,m = map(int,input().split())
g = [[] for _ in range(n+1)]
edges = []
for _ in range(m):
    a,b = map(int,input().split())
    edges.append((a,b))
    g[a].append(b)
    g[b].append(a)
ans = 0
for a,b in edges:
    cnct = [False for _ in range(n+1)]
    cnct[a] = True
    que = deque([])
    for k in g[a]:
        if k!=b:
            que.append(k)
    while que:
        p = que.pop()
        if cnct[p] == True:
            continue
        else:
            cnct[p] = True
            for k in g[p]:
                que.append(k)
    if cnct[b] == False:
        ans += 1
print(ans)

Solution (Python):
N, M = map(int, input().split())

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


def dfs(p, i, arrived):
    for n in G[p]:
        if arrived[n] is False and tuple(sorted((p, n))) != R[i]:
            arrived[n] = True
            dfs(n, i, arrived)


ans = 0
for i in range(M):
    arrived = [False]*N
    arrived[0] = True
    dfs(0, i, arrived)
    if not all(arrived):
        ans += 1
print(ans)

Solution (Python):
from collections import deque
N,M=map(int,input().split())
ab=[tuple(map(int,input().split())) for _ in range(M)]
ans=0
for i in range(M):
    tab=ab[:]
    tab.pop(i)
    r=[[] for _ in range(N)]
    for a,b in tab:
        r[a-1].append(b-1)
        r[b-1].append(a-1)
    l=[True]*N
    l[0]=False
    q=deque(r[0])
    while q:
        t=q.popleft()
        if l[t]:
            l[t]=False
            for j in r[t]:
                if r[j]:
                    q.append(j)
    ans+=any(l)
print(ans)

Solution (Python):
def BFS(graph):
    flags = [False]*n
    deque = collections.deque()
    deque.append(min(graph.keys()))
    while len(deque) > 0:
        item = deque.popleft()
        for i in graph[item]:
            if flags[i-1] == False:
                deque.append(i)
                flags[i-1] = True
    return all(flags)

import collections
def solve(n, m, ab_list):
    count = 0

    for i in range(m):
        graph = {}
        tmp_list = ab_list.copy()
        tmp_list.pop(i)
        for a, b in tmp_list:
            if a not in graph:
                graph[a] = []

            if b not in graph:
                graph[b] = []

            graph[a].append(b)
            graph[b].append(a)
        tmp = BFS(graph)
        if tmp == False:
            count += 1

    return count

if __name__ == "__main__":
    n, m = [int(i) for i in input().split()]
    ab_list = [[int(j) for j in input().split()] for i in range(m)]
    print(solve(n, m, ab_list))

Solution (Python):
import sys
readline = sys.stdin.readline
from collections import deque

def is_connected(path, N):
    visited = [False] * N
    visited[0] = True
    que = deque([0])
    while que:
        pre = que.popleft()
        for next in range(N):
            if not visited[next] and path[pre][next]:
                visited[next] = True
                que.append(next)
    
    if sum(visited) == N:
        return True
    else:
        return False

def main():
    N, M = map(int, readline().rstrip().split())
    path = [[False] * N for _ in range(N)]
    edge = []
    for _ in range(M):
        a, b = map(int, readline().rstrip().split())
        edge.append((a-1, b-1))
        path[a-1][b-1] = True
        path[b-1][a-1] = True
    
    res = 0
    for a, b in edge:
        path[a][b] = False
        path[b][a] = False

        if not is_connected(path, N):
            res += 1

        path[a][b] = True
        path[b][a] = True

    print(res)


if __name__ == '__main__':
    main()

Solution (Python):
import sys
input = sys.stdin.readline
def find(x):
    if par[x] < 0:
        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 False
    else:
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True
    
def same(x,y):
    return find(x) == find(y)

def size(x):
    return -par[find(x)]
def func(a):
    return int(a)-1
n,m = map(int,input().split())
par = [-1]*n
ab = [list(map(func,input().split()))for i in range(m)]
ans = 0
for i in range(m):
    par = [-1]*n
    for j in range(m):
        if i != j:
            unite(ab[j][0],ab[j][1])
    for k in range(m):
        if not(same(ab[k][0],ab[k][1])):
            
            ans += 1
            break

print(ans)

Solution (Python):
import copy
def main():
  global graph,vis,n
  n,m,*ab = map(int,open(0).read().split())
  ab = [(ab[i]-1,ab[i+1]-1) for i in range(0,len(ab),2)]
  master_graph = [[False]*n for _ in range(n)]
  for i,j in ab:
    master_graph[i][j] = True
    master_graph[j][i] = True
  ans = 0
  for i,j in ab:
    graph = copy.deepcopy(master_graph)
    graph[i][j] = False
    graph[j][i] = False
    vis = [False]*n
    dfs(0)
    if not(all(vis)):
      ans += 1
  print(ans)

def dfs(x):
  if not vis[x]:
    vis[x] = True
    for i in range(n):
      if graph[x][i]:
        dfs(i)

main()

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

import numpy as np
from collections import deque

def abc075_c():
    N, _ = map(int, readline().strip().split())
    edge_list = []  
    adj_mtx = np.zeros((N, N), dtype=int)  
    for ln in readlines():
        a, b = map(int, ln.strip().split())
        edge_list.append((a-1, b-1))
        adj_mtx[a-1, b-1] = adj_mtx[b-1, a-1] = 1

    def bfs(start: int, W: list):
        que = deque()  
        dist = [-1] * len(W)  
        que.append(start)  
        dist[start] = 0  
        while que:
            here = que.popleft()  
            
            for i, node in enumerate(W[here]):
                if node == 0: continue  
                if dist[i] != -1: continue  
                dist[i] = dist[here] + 1  
                que.append(i)  
        return dist

    ans = 0
    for a, b in edge_list:
        
        adj_mtx[a, b] = adj_mtx[b, a] = 0
        
        dist = bfs(0, adj_mtx.tolist())
        if -1 in dist: ans += 1
        
        adj_mtx[a, b] = adj_mtx[b, a] = 1

    print(ans)

abc075_c()

Solution (Python):

from collections import deque

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

edge = [[] for _ in range(n)]  
for i in range(m):
    a, b = map(int, ab[i].split())
    a, b = a - 1, b - 1
    
    edge[a].append((b, i))
    edge[b].append((a, i))
ans = 0
for i in range(m):  
    visit = [0] * n
    visit[0] = 1
    stack = deque()
    stack.append(0)
    while stack:
        pos = stack.popleft()
        for j in edge[pos]:
            if j[1] == i or visit[j[0]]:  
                pass
            else:
                stack.append(j[0])
                visit[j[0]] = 1
    
    if sum(visit) != n:
        ans += 1
print(ans)

Solution (Python):
class UnionFind:
    def __init__(self,n):
        self.n=n
        self.parents=[-1]*n
        self.rank=[0]*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.rank[x]<self.rank[y]:
            self.parents[y]+=self.parents[x]
            self.parents[x]=y
        else:
            self.parents[x]+=self.parents[y]
            self.parents[y]=x

            if self.rank[x]==self.rank[y]:
                self.rank[x]+=1

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

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

    def group_count(self):
        count=0
        for e in self.parents:
            if e<0: count+=1
        return count

from sys import stdin
def main():
    
    readline=stdin.readline
    N,M=map(int,readline().split())
    a=[0]*M
    b=[0]*M
    for i in range(M):
        a[i],b[i]=map(lambda x:int(x)-1,readline().split())
    
    res=0
    for i in range(M):
        t=UnionFind(N)
        for j in range(M):
            if j==i:
                pass
            else:
                t.union(a[j],b[j])
        if t.group_count()==2:
            res+=1
    
    print(res)

if __name__=="__main__":
    main()

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())
edge = []
for _ in range(M):
    u, v = map(int, input().split())
    edge.append((u-1, v-1))
cnt = 0
for i in range(M):
    uf = UnionFind(N)
    for j in range(M):
        a, b = edge[j]
        if i != j:
            uf.union(a, b)
    if uf.group_count() > 1:
        cnt += 1
print(cnt)

Solution (Python):
import sys
input = sys.stdin.readline  
sys.setrecursionlimit(10 ** 7)  


def dfs(G, v, visited):
    """G: graph, v: vertex"""
    visited[v] = True
    for c in G[v]:
        if visited[c]:
            continue
        dfs(G, c, visited)


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

    ans = 0
    for i in range(M):
        
        G[a[i]].remove(b[i])
        G[b[i]].remove(a[i])

        visited = [False] * N
        visited[0] = True
        dfs(G, 0, visited)

        if visited.count(True) != N:
            ans += 1

        
        G[a[i]].append(b[i])
        G[b[i]].append(a[i])

    print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10**6)

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



def dfs(s, check, a, b):
    for t in G[s]:
        if (s, t) == (a, b) or (s, t) == (b, a):
            continue
        if check[t]:
            continue
        check[t] = 1
        dfs(t, check, a, b)
    if 0 in check:
        return 1
    else:
        return 0

cnt = 0
for a, b in edge:
    check = [1] + [0] * (N-1)
    cnt += dfs(0, check, a, b)
print(cnt)

Solution (Python):
import sys

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, sys.stdin.readline().rstrip().split())
edges = []
for _ in range(M):
    a, b = map(int, sys.stdin.readline().rstrip().split())
    edges.append((a-1, b-1))

ans = 0
for i in range(M):
    uf = UnionFind(N)
    for j, (a, b) in enumerate(edges):
        if i == j:
            continue
        uf.union(a, b)
    if uf.group_count() != 1:
        ans += 1

print(ans)

Solution (Python):
class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]
    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 x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]
    def is_same(self, x, y):
        return self.find(x) == self.find(y)
    def get_size(self, x):
        x = self.find(x)
        return self.size[x]
    def get_group(self):
        a=0
        for i in range(len(self.par)):
          if self.find(i)==i:
            a+=1
        return a
N,M=map(int,input().split())
AB=[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:
      continue
    a,b=AB[j]
    uf.union(a-1,b-1)
  if uf.get_group()!=1:
    ans+=1
print(ans)

Solution (Python):
import sys
from io import StringIO
import unittest

sys.setrecursionlimit(10**5)

def dfs(u, visited, g, seq):
	visited[u] = True
	for v in g[u]:
		if visited[v] == True or not seq[u][v]:
			continue
		dfs(v, visited, g, seq)

def resolve():
	n, m = map(int, input().split())
	seq = [[True]*n for _ in range(n)]
	g = [[] for _ in range(n)]
	edges = []
	ans = 0
	for _ in range(m):
		a, b = map(int, input().split())
		edges.append([a-1, b-1])
	for i in range(m):
		g[edges[i][0]].append(edges[i][1])
		g[edges[i][1]].append(edges[i][0])

	for i in range(m):
		visited = [False]*n

		seq[edges[i][1]][edges[i][0]] = False
		seq[edges[i][0]][edges[i][1]] = False

		dfs(0, visited, g, seq)
		if len(visited) != visited.count(True):
			ans += 1
		seq[edges[i][1]][edges[i][0]] = True
		seq[edges[i][0]][edges[i][1]] = True
	print(ans)
resolve()