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):
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())
path = [list(map(int, input().split())) for i in range(M)]
ans = 0
for i in range(M):
    flag = 1
    bridge = UnionFind(N)
    for j in range(M):
        if i != j:
            bridge.union(path[j][0]-1, path[j][1]-1)
    for j in range(N):
        if not(bridge.same(0, j)):
            
            flag = 0
    if not(flag):
        ans += 1
print(ans)

Solution (Python):
import sys

sys.setrecursionlimit(10**7)


def dfs(x):
    if arrival[x-1]==1:
        return
    else:
        arrival[x-1]=1
        for i in mapi[x-1]:
            dfs(i)
        return

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

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

count=0
for i in range(m):
    li=l[0:i]+l[i+1:m]
    mapi=[[] for a in range(n)]
    for j in range(m-1):
        mapi[li[j][0]-1].append(li[j][1])
        mapi[li[j][1]-1].append(li[j][0])
    arrival=[0 for a in range(n)]
    dfs(1)
    if 0 in arrival:
        count+=1
print(count)

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

parent = None
def root(a):
  if parent[a] == a:
    return a
  else:
    parent[a] = root(parent[a])
    return parent[a]

def is_same(a,b):
  return root(a) == root(b)

def unite(a,b):
  ra = root(a)
  rb = root(b)
  if ra == rb:
    return
  parent[ra] = rb

ans = 0
for i in range(M):
  parent = [k for k in range(N)]
  for j,e in enumerate(es):
    if j == i:
      continue
    a,b = e
    unite(a,b)
  a,b = es[i]
  if not is_same(a,b):
    ans += 1
print(ans)

Solution (Python):
import sys
import os
import math
import bisect
import collections
import itertools
import heapq
import re
import queue
from decimal import Decimal



sys.setrecursionlimit(10000000)

ii = lambda: int(sys.stdin.buffer.readline().rstrip())
il = lambda: list(map(int, sys.stdin.buffer.readline().split()))
fl = lambda: list(map(float, sys.stdin.buffer.readline().split()))
iln = lambda n: [int(sys.stdin.buffer.readline().rstrip()) for _ in range(n)]

iss = lambda: sys.stdin.buffer.readline().decode().rstrip()
sl = lambda: list(map(str, sys.stdin.buffer.readline().decode().split()))
isn = lambda n: [sys.stdin.buffer.readline().decode().rstrip() for _ in range(n)]

lcm = lambda x, y: (x * y) // math.gcd(x, y)


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


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

    def root(self, N):
        if self.tree[N] == N:
            return N
        else:
            self.tree[N] = self.root(self.tree[N])
            return self.tree[N]

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

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
        else:
            self.tree[x] = y


def main():
    if os.getenv("LOCAL"):
        sys.stdin = open("input.txt", "r")

    N, M = il()
    XY = [il() for _ in range(M)]

    ret = 0
    for i in range(M):
        uf = UnionFind(N)
        for j in range(M):
            if i != j:
                x, y = XY[j]
                uf.unite(x - 1, y - 1)
        x, y = XY[i]
        if not uf.same(x - 1, y - 1):
            ret += 1
    print(ret)


if __name__ == '__main__':
    main()

Solution (Python):
from collections import deque

N, M = map(int, input().split())
ans = 0
roads = [list(map(int, input().split())) for _ in range(M)]
for i in range(M):
  G = [[]*N for _ in range(N)]
  for j in range(M):
    if j == i:
      continue
    a, b = roads[j]
    G[a-1].append(b-1)
    G[b-1].append(a-1)
  
  stack = deque([0])
  visited = [False] * N
  visited[0] = True
  while stack:
    now = stack.pop()
    for nxt in G[now]:
      if visited[nxt]:
        continue
      visited[nxt] = True
      stack.append(nxt)
      
  for f in visited:
    if not f:
      ans += 1
      break
      
print(ans)

Solution (Python):
N, M = map(int, input().split())
l = []
for _ in range(M):
    a,b = list(map(int, input().split()))
    l.append([a-1,b-1])
visit = [0]*N
graph = [0]*N*N
g = []
def dfs(v):
  visit[v] = 1
  for v2 in range(N):
    if graph[v*N+v2] == 1 and visit[v2] == 0:
      g.append(v2)
    if v2 == N-1 and len(g) != 0:
      a = g[0]
      g.pop(0)
      return dfs(a)
ans = 0
for a,b in l:
  graph[a*N+b] = graph[b*N+a] = 1
for a,b, in l:
  graph[a*N+b] = graph[b*N+a] = 0
  visit = [0]*N
  dfs(0)
  if sum(visit) != N:
    ans += 1
  graph[a*N+b] = graph[b*N+a] = 1
print(ans)

Solution (Python):
import sys

sys.setrecursionlimit(10000000)
import os
import math
import bisect
import collections
import itertools
import heapq
import re
import queue
from decimal import Decimal



ii = lambda: int(sys.stdin.buffer.readline().rstrip())
il = lambda: list(map(int, sys.stdin.buffer.readline().split()))
fl = lambda: list(map(float, sys.stdin.buffer.readline().split()))
iln = lambda n: [int(sys.stdin.buffer.readline().rstrip()) for _ in range(n)]

iss = lambda: sys.stdin.buffer.readline().decode().rstrip()
sl = lambda: list(map(str, sys.stdin.buffer.readline().decode().split()))
isn = lambda n: [sys.stdin.buffer.readline().decode().rstrip() for _ in range(n)]

lcm = lambda x, y: (x * y) // math.gcd(x, y)


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


def dfs(s, graph, bridge, visit):
    visit[s] = True
    for next in graph[s]:
        if not bridge[s][next]: continue
        if visit[next]: continue
        dfs(next, graph, bridge, visit)


def main():
    if os.getenv("LOCAL"):
        sys.stdin = open("input.txt", "r")

    N, M = il()
    graph = {n: [] for n in range(N)}

    for _ in range(M):
        a, b = il()
        graph[a - 1].append(b - 1)
        graph[b - 1].append(a - 1)

    ret = 0
    bridge = {n: [True] * N for n in range(N)}
    searched = {n: [False] * N for n in range(N)}
    for i in range(N):
        for j in graph[i]:
            if searched[i][j]: continue
            searched[i][j],searched[j][i] = True, True
            visit = [False] * N
            bridge[i][j],bridge[j][i] = False, False
            dfs(0, graph, bridge, visit)
            if not all(visit): ret += 1
            bridge[i][j], bridge[j][i] = True, True
    print(ret)


if __name__ == '__main__':
    main()

Solution (Python):
import sys

sys.setrecursionlimit(10000000)
import os
import math
import bisect
import collections
import itertools
import heapq
import re
import queue
from decimal import Decimal



ii = lambda: int(sys.stdin.buffer.readline().rstrip())
il = lambda: list(map(int, sys.stdin.buffer.readline().split()))
fl = lambda: list(map(float, sys.stdin.buffer.readline().split()))
iln = lambda n: [int(sys.stdin.buffer.readline().rstrip()) for _ in range(n)]

iss = lambda: sys.stdin.buffer.readline().decode().rstrip()
sl = lambda: list(map(str, sys.stdin.buffer.readline().decode().split()))
isn = lambda n: [sys.stdin.buffer.readline().decode().rstrip() for _ in range(n)]

lcm = lambda x, y: (x * y) // math.gcd(x, y)


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


def dfs(s, graph, bridge, visit):
    visit[s] = True
    for next in graph[s]:
        if not bridge[s][next]: continue
        if visit[next]: continue
        dfs(next, graph, bridge, visit)


def main():
    if os.getenv("LOCAL"):
        sys.stdin = open("input.txt", "r")

    N, M = il()
    graph = {n: [] for n in range(N)}

    for _ in range(M):
        a, b = il()
        graph[a - 1].append(b - 1)
        graph[b - 1].append(a - 1)

    ret = 0
    bridge = {n: [True] * N for n in range(N)}
    for i in range(N):
        for j in graph[i]:
            visit = [False] * N
            bridge[i][j],bridge[j][i] = False, False
            dfs(0, graph, bridge, visit)
            if not all(visit): ret += 1
            bridge[i][j], bridge[j][i] = True, True
    print(ret//2)


if __name__ == '__main__':
    main()

Solution (Python):
def dfs(node, visited, g):
    visited[node] = True
    for neib in g[node]:
        if not visited[neib]:
            dfs(neib, visited,g)


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

ans = 0
for i in range(M):
    g = [ [] for _ in range(N+1)]
    for j, ab in enumerate(abl):
        if j == i: continue
        a,b = ab
        g[a].append(b)
        g[b].append(a)
    visited = [False] * (N+1)
    visited[0] = True
    dfs(1, visited, g)
    if False in visited:
        ans+=1 

print(ans)

Solution (Python):
from collections import defaultdict
from heapq import heappop, heappush


class Graph(object):
    """
    隣接リストによる有向グラフ
    """

    def __init__(self):
        self.graph = defaultdict(list)

    def __len__(self):
        return len(self.graph)

    def add_edge(self, src, dst, weight=1):
        self.graph[src].append((dst, weight))

    def get_nodes(self):
        return self.graph.keys()


class Dijkstra(object):
    """
    ダイクストラ法（二分ヒープ）による最短経路探索
    計算量: O((E+V)logV)
    """

    def __init__(self, graph, start):
        self.g = graph.graph

        
        
        self.dist = defaultdict(lambda: float('inf'))
        self.dist[start] = 0

        
        self.prev = defaultdict(lambda: None)

        
        self.Q = []
        heappush(self.Q, (self.dist[start], start))

        while self.Q:
            
            dist_u, u = heappop(self.Q)
            if self.dist[u] < dist_u:
                continue
            for v, weight in self.g[u]:
                alt = dist_u + weight
                if self.dist[v] > alt:
                    self.dist[v] = alt
                    self.prev[v] = u
                    heappush(self.Q, (alt, v))

    def shortest_distance(self, goal):
        """
        startノードからgoalノードまでの最短距離
        """
        return self.dist[goal]

    def shortest_path(self, goal):
        """
        startノードからgoalノードまでの最短経路
        """
        path = []
        node = goal
        while node is not None:
            path.append(node)
            node = self.prev[node]
        return path[::-1]


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

    ans = 0
    for i in range(M):
        g = Graph()
        for j in range(M):
            if j == i:
                continue
            else:
                g.add_edge(ab[j][0], ab[j][1])
                g.add_edge(ab[j][1], ab[j][0])
        tmp = Dijkstra(g, ab[i][0])
        if tmp.shortest_distance(ab[i][1]) == float('inf'):
            ans += 1

    print(ans)


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 roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

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


def main():
    n, m = map(int, input().split())
    a, b = [], []
    for i in range(m):
        A, B = map(int, input().split())
        a.append(A - 1)
        b.append(B - 1)
    
    ans = 0
    for i in range(m):
        uf = UnionFind(n)
        for j in range(m):
            if i == j:
                continue
            uf.union(a[j], b[j])
        if uf.group_count() != 1:
            ans += 1
            
    print(ans)

if __name__ == '__main__':
    main()

Solution (Python):
from collections import deque


class UnionFind:
    def __init__(self, v):
        self.v = v
        self._tree = list(range(v + 1))

    def _root(self, a):
        queue = deque()
        while self._tree[a] != a:
            queue.append(a)
            a = self._tree[a]
        while queue:
            index = queue.popleft()
            self._tree[index] = a
        return a

    def union(self, a, b):
        root_a = self._root(a)
        root_b = self._root(b)
        self._tree[root_b] = root_a

    def find(self, a, b):
        return self._root(a) == self._root(b)


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

bridges = 0
for a1, b1 in edges:
    union_find = UnionFind(N)
    for a2, b2 in edges:
        if a1 == a2 and b1 == b2:
            continue
        union_find.union(a2, b2)
    if not union_find.find(a1, b1):
        bridges += 1

print(bridges)

Solution (Python):

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)]
n,m = map(int,input().split())


par = [-1]*n
count = 0
graph = []
for i in range(m):
    x,y = map(int,input().split())
    x -= 1
    y -= 1
    graph.append([x,y])
for i in range(m):
    p = [j for j in range(n)]
    par = [-1]*n
    for j in range(m):
        if i != j:
            unite(graph[j][0],graph[j][1])
    if not((-1)*n in par):
        count+=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()}

(n, m), *q = [list(map(int, i.split())) for i in open(0)]
c = 0
for i in range(m):
    UF = UnionFind(n)
    for j, (a, b) in enumerate(q):
        if i == j:
            continue
        UF.union(a - 1, b - 1)
    if UF.group_count() > 1:
        c += 1
print(c)

Solution (Python):
class UnionFind:
    def __init__(self, n=1):
        self.parent = [i for i in range(n)]
        self.rank = [0] * n
    
    def find(self, x):
        if self.parent[x] == x:
            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:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.parent[y] = x
    
    def is_same(self, x, y):
        return self.find(x) == self.find(y)

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, (a, b) in enumerate(ab):
    if i == j:
      continue
    uf.union(a-1, b-1)
  root = set([uf.find(j) for j in range(N)])
  if len(root) >= 2:
    ans += 1

print(ans)

Solution (Python):
import sys
sys.setrecursionlimit(100000)

def DFS(i,a,b):
    if i not in done:
        done.append(i)
        for f in g[i]:
            if [i,f]==[a,b] or [i,f]==[b,a]:
                continue
            else:
                DFS(f,a,b)
    else:
        return

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

ans=0
for i in range(M):
    done=[]
    DFS(0,edge[i][0],edge[i][1])
    if len(done)<N:
        ans+=1

print(ans)

Solution (Python):
n,m = map(int, input().split())

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


def dfs(source):
    dist = [-1]*(n+1)
    dist[source] = 0
    q = [source]
    while q:
        a = q.pop()
        for b in V[a]:
            if dist[b]!=-1:
                continue
            dist[b] = dist[a] + 1
            q.append(b)
    return dist

from collections import defaultdict
import collections

res = 0
for i in range(m):
    abc = ab.copy()
    del abc[i]
    V = defaultdict(list)

    for _ in range(m-1):
        a, b = abc[_][0],abc[_][1]
        V[a].append(b)
        V[b].append(a)
    d1 =dfs(1)
    c = collections.Counter(d1)
    if c[-1] >1:
        res +=1
print(res)

Solution (Python):
import math

import queue
from collections import deque,defaultdict
import heapq
from sys import stdin,setrecursionlimit


ipt = stdin.readline
setrecursionlimit(10**7)

def main():
    n,m = map(int,ipt().split())
    way = [[] for _ in [0]*n]
    for i in range(m):
        a,b = map(int,ipt().split())
        way[a-1].append((b-1,i))
        way[b-1].append((a-1,i))
    ans = 0
    q = queue.Queue()
    for i in range(m):
        al = [-1 for i in range(n)]
        q.put(0)
        al[0] = 0
        while not q.empty():
            qi = q.get()
            for j,wn in way[qi]:
                if wn == i or al[j] == 0:
                    continue
                else:
                    al[j] = 0
                    q.put(j)
        if -1 in al:
            ans += 1

    print(ans)

    return

if __name__ == '__main__':
    main()

Solution (Python):
import copy
n,m=map(int,input().split())
temp=[[] for i in range(n)]
for i in range(m):
  a,b=map(int,input().split())
  a=a-1
  b=b-1
  temp[a].append(b)
  temp[b].append(a)
count=0
a=[]
c=True
while c:
  c=False
  for i in range(n):
    if len(temp[i])==1 and i not in a:
      temp[temp[i][0]].remove(i)
      a.append(i)
      count=count+1
      c=True
print(count)

Solution (Python):
N, M = map(int, input().split())
edges = [[] for _ in range(N)]
ans = 0

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

changed = True
sumi = []
count = 0
while changed:
    changed = False
    for i in range(len(edges)):
        if len(edges[i]) == 1 and i not in sumi:
            edges[edges[i][0]].remove(i)
            sumi.append(i)
            changed = True
            count += 1
print(count)

Solution (Python):
from collections import deque
num_ver, num_edge = map(int,input().split())
edges_ls = [0] * num_edge
for i in range(num_edge):
    a,b = map(int,input().split())
    a -= 1
    b -= 1
    edges_ls[i] = [a,b]

num_bridge = 0
for ind_take_edge in range(num_edge):
    graph_ls = [[] for _ in range(num_ver)]
    
    for ind_edge in range(num_edge):
        if ind_edge != ind_take_edge:
            a,b = edges_ls[ind_edge]
            graph_ls[a].append(b)
            graph_ls[b].append(a)
    
    
    done_ls = [0] * num_ver
    queue = deque()
    queue.append(0)
    while queue:
        now = queue.pop()
        done_ls[now] = 1
        for nex in graph_ls[now]:
            if done_ls[nex] != 1:
                queue.append(nex)
    
    if sum(done_ls) != num_ver:
        num_bridge += 1

print(num_bridge)

Solution (Python):

import numpy as np
n,m = list(map(int,input().rstrip().split()))
graph = [[] for _ in range(n)]
route_list = []
for _ in range(m):
    a,b = list(map(int,input().rstrip().split()))
    a -=1
    b -=1
    route_list.append([a,b])
    graph[a].append(b)
    graph[b].append(a)

def dfs(mask, p,graph):
    mask[p] = 1
    if mask.all():
        return True
    nexts = graph[p]
    for n in nexts:
        if mask[n] == 1:
            continue
        else:
            if dfs(mask,n,graph):
                return True
    return False

counter = 0
for r in route_list:
    graph[r[0]].remove(r[1])
    graph[r[1]].remove(r[0])
    mask = np.zeros(len(graph),int)
    if dfs(mask,0,graph) == False:
        counter += 1
    graph[r[0]].append(r[1])
    graph[r[1]].append(r[0])
print(counter)

Solution (Python):
import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy, copy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left, insort, insort_left
from fractions import gcd
from heapq import heappush, heappop
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7



class UnionFind():
    def __init__(self, n):
        self.n = n
        
        
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[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.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 0 > x]
    
    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()
ab = [LIST() for _ in range(M)]
ans = 0

for i in range(M):
	tree = UnionFind(N)
	for j in range(M):
		if j != i:
			tree.union(ab[j][0]-1, ab[j][1]-1)
	if tree.group_count() == 2:
		ans += 1

print(ans)

Solution (Python):
class UnionFind:
    def __init__(self, n):
        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[x] += 1

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

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

bridge = [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 = bridge[j]
         if not UF.same_check(a, b):
            UF.union(a, b)
    flag = 0
    for k in range(1, N+1):
        if UF.par[k] == k:
            flag += 1
    if flag != 1:
        ans += 1
print(ans)

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


def main():
    N, M = map(int, input().split())
    a, b = [], []
    for _ in range(M):
        aa, bb = map(int, input().split())
        a.append(aa - 1)
        b.append(bb - 1)
    count = 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 uf.group_count() != 1:
            count += 1
    print(count)

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

Solution (Python):
def dfs_traverse(adj, visited, u=0):
  visited[u] = True
  for v in adj[u]:
    if not visited[v]:
      dfs_traverse(adj, visited, v)


def calc_num_of_bridges(edges, adj):
  n = len(adj)
  bridge_cnt = 0
  for a, b in edges:
    adj[a].remove(b)
    adj[b].remove(a)
    
    visited = [False] * n
    dfs_traverse(adj, visited)
    if not all(visited):
      bridge_cnt += 1
    
    adj[a].append(b)
    adj[b].append(a)
  return bridge_cnt


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

print(calc_num_of_bridges(edges, adj))

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

road = [[] for _ in range(N)]

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

def dfs(v,w):
  l = [0 for _ in range(N)]
  l[v] = 1
  stack = [v]
  while stack:
    vv = stack.pop()
    for i in road[vv]:
      if i == w and v == vv or i == vv and v == w:
        continue
      else:
        if l[i] == 0:
          l[i] = 1
          stack.append(i)
  return sum(l)

ans = 0
check = [[0 for _ in range(N)] for _ in range(N)]

for n in range(N):
  for m in range(len(road[n])):
    if check[n][road[n][m]] == 0 or check[road[n][m]][n] == 0:
      check[n][road[n][m]] = 1
      check[road[n][m]][n] = 1
      d = dfs(n,road[n][m])
      if d != N:
        ans += 1

print(ans)