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):
        super().__init__()
        self.par = [-1]*n
        self.rank = [0]*n
        self.tsize = [1]*n

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

    def unite(self, x, y):
        x_r = self.root(x)
        y_r = self.root(y)
        
        if self.rank[x_r]>self.rank[y_r]:
            self.par[y_r] = x_r

        elif self.rank[x_r]<self.rank[y_r]:
            self.par[x_r] = y_r

        elif x_r != y_r:
            self.par[y_r] = x_r
            self.rank[x_r] += 1

        if x_r != y_r:
            size = self.tsize[x_r]+self.tsize[y_r]
            self.tsize[x_r] = size
            self.tsize[y_r] = size

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

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

def main():
    n,m = tuple([int(t)for t in input().split()])

    t = [tuple([int(t)-1 for t in input().split()])for _ in [0]*m]

    ans = 0
    for k in range(m):
        uf = UnionFind(n)
        for i in range(m):
            if k!=i:
                uf.unite(t[i][0],t[i][1])
        if uf.size(0) !=n :ans+=1
    
    print(ans)
if __name__ == "__main__":
    main()

Solution (Python):
n,m = map(int,input().split())
s = [list(map(int,input().split())) for i in range(m)]
ans = 0
for i in s:
    l = list(range(n))
    for j in s:
        if i!=j:
            l=[l[j[0]-1] if l[k]==l[j[1]-1] else l[k] for k in range(n)]
    if len(set(l))!=1: ans+=1
print(ans)

Solution (Python):
N,M=map(int,input().split())
E=[[] for _ in range(N)]
lst=[]
for i in range(M):
  x,y=map(int,input().split())
  x-=1
  y-=1
  E[x].append(y)
  E[y].append(x)
  lst.append((x,y))
cnt=0
for x,y in lst:
  stack=[0]
  seen=[0]*N
  seen[0]=1
  while stack:
    u=stack.pop()
    for v in E[u]:
      if (u==x and v==y)or (u==y and v==x):
        pass
      else:
        if seen[v]==0:
          seen[v]=1
          stack.append(v)
  if sum(seen)==N:
    pass
  else:
    cnt+=1
print(cnt)

Solution (Python):
class UnionFind:

    def __init__(self, n):
        self.p, self.d = [-1] * n, [0] * n

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

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

    def unite(self, x, y):
        if self.isSame(x, y):
            return
        x, y = self.find(x), self.find(y)

        if self.d[x] > self.d[y]:
            self.p[x] += self.p[y]
            self.p[y] = x
        else:
            self.p[y] += self.p[x]
            self.p[x] = y
            if self.d[x] == self.d[y]:
                self.d[y] += 1

    def numTree(self):
        return sum([1 for p in self.p if p < 0])


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

ans = 0
for i in range(M):
    U = UnionFind(N)
    for a, b in E[:i] + E[i + 1:]:
        U.unite(a - 1, b - 1)
    if U.numTree() == 2:
        ans += 1

print(ans)

Solution (Python):
icase=0
if icase==0:
    n,m=map(int, input().split())
    a=[]
    b=[]
    for i in range(m):
        ai,bi=map(int, input().split())
        a.append(ai)
        b.append(bi)
elif icase==1:
    n=6
    m=5


    a=[1,2,3,4,5]
    b=[2,3,4,5,6]
elif icase==2:
    n=7
    m=7
    a=[1,2,3,4,4,5,6]
    b=[3,7,4,5,6,6,7]

    
vtx=[]
for i in range(n):
    vtx.append([i+1])
icnt=0

for j in range(m):    
    vtx1=vtx.copy()
    a1=a.copy()
    b1=b.copy()
    del a1[j]
    del b1[j]
    
    for i in range(m-1):
        for v1 in vtx1:
            if a1[i] in v1:
                if not b1[i] in v1:
                    for v2 in vtx1:
                        if v1!=v2:
                            if b1[i] in v2:
                                break
                    vtx1.remove(v1)
                    vtx1.remove(v2)
                    v3=v1+v2
                    vtx1.append(v3)


    if len(vtx1)!=1:
        icnt=icnt+1
print(icnt)

Solution (Python):


from collections import deque


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

    result = 0

    for i in AB:
        b = AB[:]
        start = i[0]
        goal = i[1]
        b.remove(i)
        q = deque()
        q.append(start)

        searched = {start}
        while q:
            current = q.popleft()
            if current == goal:
                break
            for j in b:
                if current == j[0] and j[1] not in searched:
                    q.append(j[1])
                    searched.add(j[1])
                elif current == j[1] and j[0] not in searched:
                    q.append(j[0])
                    searched.add(j[0])
        else:
            result += 1

    print(result)


if __name__ == "__main__":
    main()

Solution (Python):
import sys
input = lambda: sys.stdin.readline().rstrip()
from itertools import accumulate

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


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

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

    if x == y:
        return
    if x > y:
        x, y = y, x

    parents[x] += parents[y]
    parents[y] = x    

def same(x,y):

    return find(x) == find(y)

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

for i in range(M):
    parents = [-1] * N
    tmp1, tmp2 = edges[i]
    for j in range(M):
        if i == j: continue
        a,b = edges[j]
        union(a,b)

    if not same(tmp1, tmp2):
        ans += 1

print(ans)

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

def dfs(num):
    temp = [num]
    visited = [0]*N
    
    while temp:
        p = temp.pop()
        for i in ab[p]:
            if visited[i] == 0:
                visited[i] = 1
                temp.append(i)
    if sum(visited)==N: jdg = False
    else: jdg = True
    return jdg

ans = 0 
for a,b in AB:
    ab = [[] for _ in range(N)]
    for a1, b1 in AB:
        if a1==a and b1==b:continue
        ab[a1-1].append(b1-1)
        ab[b1-1].append(a1-1)
        
    if dfs(a):ans += 1
print(ans)

Solution (Python):
import copy
def is_linking(sides):
    side = copy.copy(sides.pop())
    flag = True
    while flag:
        if not sides:
            if len(side) == n:
                return True
            else:
                return False
        for i in range(len(sides)):
            if side & sides[i]:
                side |= sides.pop(i)
                break
            elif i == len(sides) - 1:
                flag = False
    if len(side) == n:
        return True
    else:
        return False       
    
n, m = map(int, input().split())
all_sides = [set(input().split()) for _ in range(m)]
count = 0
for i in range(m):
    sides = all_sides[:i] + all_sides[i+1:]
    if is_linking(sides):
        continue
    else:
        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()}

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




n,m=map(int,input().split())
uf=UnionFind(n)
ans=0
a=[[int(i) for i in input().split()]for i in range(m)]

for i in a:
    x,y=i
    uf.union(x-1,y-1)
cnt=uf.group_count()

for i in range(m):
    uf_new=UnionFind(n)
    for j in range(m):
        x,y=a[j]
        if j==i:
            continue
        uf_new.union(x-1,y-1)
    cnt_new=uf_new.group_count()
    if cnt!=cnt_new:
        ans+=1
print(ans)

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



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

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


ans = 0
for i in range(M):
    par = [-1] * (N + 1)
    for j in range(M):
        if i != j:
            unite(a[j],b[j])
    if not same(a[i],b[i]):
        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)]

    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())
ab = [list(map(int,input().split())) for _ in range(m)]

ans = 0

for i in range(m):
    ab2 = ab[:i] + ab[i+1:]
    uf = UnionFind(n)
    for a,b in ab2:
        uf.union(a-1,b-1)
    if uf.group_count() > 1:
        ans += 1

print(ans)

Solution (Python):
n,m= map(int,input().split())
henl = []
usehen = [False] * m
brdic = {}
for _ in range(m):
    a,b= map(int,input().split())
    brdic[a] = brdic.get(a,[]) + [b]
    brdic[b] = brdic.get(b,[]) + [a]
    henl.append((a,b))

ordin = [-1]*(n+1)
lowlink = [-1]*(n+1)
k=[1]
bn=[0]
def dfs(node):
    ordin[node]=k[0]
    k[0]+=1
    lowlink[node]=ordin[node]
    for br in brdic[node]:
        temp = (min(node,br),max(node,br))
        if ordin[br]==-1:
            usehen[henl.index(temp)]=True
            dfs(br)
            lowlink[node] = min(lowlink[br],lowlink[node])
        else:
            if usehen[henl.index(temp)]==False:lowlink[node] = min(ordin[br],lowlink[node])
        if ordin[node] < lowlink[br]:bn[0]+=1
dfs(1)
print(bn[0])

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


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

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

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

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.rank[x] < self.rank[y]:
            self.root[y] += self.root[x]
            self.root[x] = y
        else:
            self.root[x] += self.root[y]
            self.root[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    def getNodeLen(self, x):
        return -self.root[self.find(x)]


if __name__ == "__main__":
    N, M = map(int, input().split())
    AB = tuple(tuple(map(int, input().split())) for _ in range(M))

    ans = 0
    for i in range(M):
        uf = UF_tree(N)
        for j, (a, b) in enumerate(AB):
            if i == j:
                continue
            uf.unite(a, b)
        a, b = AB[i]
        if not uf.isSame(a, b):
            ans += 1
    print(ans)

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

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

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

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

    if x == y:
        return

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

    parents[x] += parents[y]
    parents[y] = x 

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

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

ans = 0
for i in range(M):
    parents = [-1] * N
    for j in range(M):
        if i == j:
            continue
        s, e = edges[j]
        union(s, e)
    a, b = edges[i]
    if not same(a, b):
        ans += 1
print(ans)

Solution (Python):

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

lines = set()
for _ in range(M):
    a,b = map(int, input().split())
    lines.add((a,b))


def connection_check(lines,start,goal):
    
    
    def add_connect(A,B):
        A_parent = get_parent(A)
        B_parent = get_parent(B)

        if A_parent != B_parent:
            parent_dict[B_parent] = A_parent
    
    def judge_connection(A,B):
        A_parent = get_parent(A) 
        B_parent = get_parent(B)

        if A_parent != B_parent:
            return False
        else:
            return True
    
    def get_parent(child):
        if child not in parent_dict: 
            parent_dict[child] = child
        parent = parent_dict[child]
        if parent == child:
            return parent
        else: 
            
            parent_dict[child] = get_parent(parent)
            return parent_dict[child]
    

    parent_dict = dict()
    
    for line in lines:
        A = line[0]
        B = line[1]
        add_connect(A,B)
    
    if judge_connection(start,goal) == True:
        return True
    else:
        return False
        

ans = 0

for line in lines:
    start = line[0]
    goal = line[1]
    remain_lines = copy.copy(lines) 
    remain_lines.remove(line)
    
    
    
    
    if connection_check(remain_lines,start,goal) is False:
        ans += 1

print(ans)

Solution (Python):

def inputlist(): return [int(j) for j in input().split()]
from collections import Counter


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]
N,M = inputlist()
ans = 0
ab = [0]*M
for i in range(M):
    ab[i] = inputlist()
for i in range(M):
    uf = UnionFind(N)
    for j in range(M):
        if j == i:
            continue
        uf.union(ab[j][0]-1,ab[j][1]-1)
    if len(uf.roots()) != 1:
        ans +=1
print(ans)

Solution (Python):
"""
DFS
"""
from collections import defaultdict
N,M = map(int, input().split())
pairs = []
for i in range(M):
    a,b = map(int, input().split())
    a -= 1
    b -= 1
    pairs.append((a,b))


def dfs(s):
    if visited[s]:return 0
    visited[s] = True
    ns = edges[s]
    for n in ns:
        dfs(n)
    
    
ans = 0  
for i in range(M):
    edges = defaultdict(list)
    visited = [False] * N
    for j,(a,b) in enumerate(pairs):
        if i == j: continue
        edges[b].append(a)
        edges[a].append(b)
    dfs(0)
    if sum(visited) != N:
        ans += 1
print(ans)

Solution (Python):
"""
DFS
"""
from collections import defaultdict
N,M = map(int, input().split())
pairs = []
for i in range(M):
    a,b = map(int, input().split())
    a -= 1
    b -= 1
    pairs.append((a,b))


def dfs(s):
    global visited,edges
    if visited[s]:return 0
    visited[s] = True
    ns = edges[s]
    for n in ns:
        dfs(n)
    
    
ans = 0  
for i in range(M):
    edges = defaultdict(list)
    visited = [False] * N
    for j,(a,b) in enumerate(pairs):
        if i == j: continue
        edges[b].append(a)
        edges[a].append(b)
    dfs(0)
    if sum(visited) != N:
        ans += 1
print(ans)

Solution (Python):
from collections import deque
from collections import defaultdict
edges = defaultdict(list)
N,M = map(int, input().split())
pairs = []
for i in range(M):
    a,b  = map(int, input().split())
    a -= 1
    b -= 1
    pairs.append((a,b))
ans = 0

for i in range(M):
    edges = defaultdict(list)
    s = 0
    for j,(a,b) in enumerate(pairs):
        if i == j:continue
        edges[a].append(b)
        edges[b].append(a)
        s = b
    cnt = 0
    
    
    seen = [False] * N 
    q = deque()
    q.append(b) 
    while len(q) > 0:
        e = q.popleft()
        nx = edges[e]
        for n in nx:
            if seen[n]:continue
            seen[n] = True
            q.append(n)
    if sum(seen) != N:
        ans += 1


    
print(ans)

Solution (Python):
class UnionFind:
    
    
    def __init__(self, n):
        self.N = n
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]

    
    def root(self, x):
        visited_nodes = []
        while True:
            p = self.parent[x]
            if p == x:
                
                for node in visited_nodes:
                    self.parent[node] = x
                return x
            else:
                visited_nodes.append(x)
                x = p

    
    def ifTree(self, array):
        root = self.root(array[0])
        for v in array:
            if not self.root(v) == root:
                return False
        return True

    
    

    def unite(self, x, y):
        if not self.root(x) == self.root(y):
            if self.rank[x] > self.rank[y]:
                self.parent[self.root(y)] = self.root(x)
            else:
                self.parent[self.root(x)] = self.root(y)
                if self.rank[x] == self.rank[y]:
                    self.rank[self.root(y)] += 1
            return True
        else:
            return False

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

    
    def printDebugInfo(self):
        print([self.root(i) for i in range(self.N)])


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

not_bridge_count = 0

array = [i for i in range(n)]
for i in range(m):
    tree = UnionFind(n)
    for j in range(m):
        if not j == i:
            tree.unite(edges[j][0], edges[j][1])
    if tree.ifTree(array):
        not_bridge_count += 1

print(m-not_bridge_count)

Solution (Python):
class Unionfind:
    
    def __init__(self,n):
        self.uf = [-1]*n

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

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

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

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

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

for i in range(m):
    
    u = Unionfind(n)
    for j in range(m):
        if i == j:
            continue
        u.union(l[j][0]-1,l[j][1]-1)
    count = set()
    for j in range(n):
        count.add(u.find(j))
    
    if len(count) > 1:
        ans += 1
print(ans)

Solution (Python):

from collections import deque
import sys
try:
    from typing import List
except ImportError:
    pass


def solve(N: int, M: int, a: "List[int]", b: "List[int]"):
    G = [[] for _ in range(N)]
    for i, (ai, bi) in enumerate(zip(a, b)):
        ai -= 1
        bi -= 1
        G[ai].append((i, bi))
        G[bi].append((i, ai))

    ans = 0
    for k in range(M):
        q = deque()
        visited = {0}
        q.append(0)
        while q:
            s = q.popleft()
            for i, t in G[s]:
                if i == k:
                    continue
                if t in visited:
                    continue
                visited.add(t)
                q.append(t)

        if len(visited) < N:
            ans += 1

    print(ans)


def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  
    M = int(next(tokens))  
    a = [int()] * (M)  
    b = [int()] * (M)  
    for i in range(M):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
    solve(N, M, a, b)


if __name__ == '__main__':
    main()

Solution (Python):
f=lambda:map(int,input().split())
n,m=f()
lt=[]
ll=[[] for _ in range(n)]
for _ in range(m):
  a,b=f()
  a-=1;b-=1
  lt+=[(a,b)]
  ll[a].append(b)
  ll[b].append(a)
def dfs(x):
  if lv[x]>0: return
  lv[x]=1
  for i in range(n):
    if x in ll[i]: dfs(i)
c=0
for a,b in lt:
  ll[a].remove(b)
  ll[b].remove(a)
  lv=[0]*n
  dfs(0)
  if sum(lv)<n: c+=1
  ll[a].append(b)
  ll[b].append(a)
print(c)

Solution (Python):
f=lambda:map(int,input().split())
n,m=f()
lt=[]
ll=[[0]*n for _ in range(n)]
for _ in range(m):
  a,b=f()
  a-=1;b-=1
  lt+=[(a,b)]
  ll[a][b]=ll[b][a]=1
def dfs(x):
  if lv[x]>0: return
  lv[x]=1
  for i in range(n):
    if ll[i][x]>0: dfs(i)
c=0
for a,b in lt:
  ll[a][b]=ll[b][a]=0
  lv=[0]*n
  dfs(0)
  if sum(lv)<n: c+=1
  ll[a][b]=ll[b][a]=1
print(c)

Solution (Python):
import copy

class UNION:
    def __init__(self):
        return
    def find(self, x):
        if par[x] < 0:
            return x
        else:
            par[x] = self.find(par[x])
            return par[x]

    
    def same(self, x, y):
        if self.self.find(x) == self.find(y):
            return True
        else:
            return False
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if par[x] > par[y]:
            x, y = y, x
        par[x] += par[y]
        par[y] = x


def uCnt(self,x):
    return -par[self.find(x)]

N, M = map(int, input().split())
ab = [list(map(int, input().split())) for _ in range(M)]
cpar = [-1 for i in range(N)]
jiko = []
for i in range(M):
    par = copy.deepcopy(cpar)
    u = UNION()
    for j in range(M):
        if j == i:continue
        a = ab[j][0] - 1
        b = ab[j][1] - 1
        u.unite(a, b)
    tmp = min(par)
    if tmp == -N:
        jiko.append(i)

par = copy.deepcopy(cpar)
u = UNION()
for i in range(M):
    if jiko.count(i) == 0:
        a = ab[i][0] - 1
        b = ab[i][1] - 1
        u.unite(a, b)
ans = 0
for i in par:
    if i < -1:
        ans += abs(i) - 1

print(ans)

Solution (Python):
def dfs(v):
    visited[v] = True
    for v2 in range(n):
        if graph[v][v2] and not visited[v2]:
            dfs(v2)


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

graph = [[False for i in range(n)] for j in range(n)]

for e in edge:
    graph[e[0]-1][e[1]-1] = True
    graph[e[1]-1][e[0]-1] = True

ans = 0

for e in edge:
    graph[e[0]-1][e[1]-1] = False
    graph[e[1]-1][e[0]-1] = False

    visited = [False for j in range(n)]

    dfs(0)

    for v in visited:
        if not v:
            ans += 1
            break

    graph[e[0]-1][e[1]-1] = True
    graph[e[1]-1][e[0]-1] = True

print(ans)

Solution (Python):
int1 = lambda x: int(x) - 1

N, M = map(int, input().split())
G = [list() for _ in range(N)]
edges = [tuple(map(int1, input().split())) for _ in range(M)]
for u,v in edges:
    G[u].append(v)
    G[v].append(u)

pre = [-1]*N
low = [-1]*N

def detect_bridge(v, p=None, c=0):
    ret = list()
    pre[v] = low[v] = c
    c += 1
    for x in G[v]:
        if x == p: continue
        if pre[x] < 0:
            br, c = detect_bridge(x, v, c)
            ret.extend(br)
             
        if low[v] > low[x]: low[v] = low[x]
    if pre[v] == low[v] > 0:
        ret.append((p, v))
    return ret, c

bridges, _ = detect_bridge(0)
print(len(bridges))

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 unite(self,x,y):
        x = self.find(x)
        y = self.find(y)
        if x==y:
            return
        if self.parents[x]>self.parents[y]:
            x,y=y,x
        self.parents[x]+=self.parents[y]
        self.parents[y]=x
    def 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=map(int,input().split())
ab=[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:continue
    uf.unite(ab[j][0]-1,ab[j][1]-1)
  if uf.group_count()==2:
    uf.unite(ab[i][0]-1,ab[i][1]-1)
    if uf.group_count()==1:
      ans+=1
print(ans)

Solution (Python):
import numpy as np
from scipy.sparse.csgraph import connected_components

n, m = list(map(int, input().split()))
edges = []
graph = np.zeros((n, n), dtype=np.int)
for _ in range(m):
    edges.append(list(map(int, input().split())))
    graph[edges[-1][0]-1][edges[-1][1]-1] += 1
    graph[edges[-1][1]-1][edges[-1][0]-1] += 1

num_of_bridges = 0
for edge in edges:
    g = graph.copy()
    g[edge[0]-1][edge[1]-1] -= 1
    g[edge[1]-1][edge[0]-1] -= 1
    if connected_components(g, return_labels=False) != 1:
        num_of_bridges += 1

print(num_of_bridges)

Solution (Python):


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

adj = [list() for _ in range(n)]

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




loop = True
bridge = 0
while loop:
    loop = False
    for i, ai in enumerate(adj):
        if len(ai) == 1:
            adj[i] = []
            adj[ai[0]].remove(i)
            bridge += 1
            loop = True


print(bridge)

Solution (Python):
import sys, re, os
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from itertools import permutations, combinations, product, accumulate
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from fractions import gcd
from heapq import heappop, heapify, heappush

def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def S_MAP(): return map(str, input().split())
def LIST(): return list(map(int, input().split()))
def S_LIST(): return list(map(str, input().split()))
 
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

N, M = MAP()
L = [LIST() for i in range(M)]

graph = defaultdict(list)

def dijkstra(E, start):
    N_d = len(E)
    dist = [INF] * N_d
    dist[start] = 0
    q = [(0, start)]
    while q:
        dist_v, v = heappop(q)
        if dist[v] != dist_v:
            continue
        for u, dist_vu in E[v]:
            dist_u = dist_v + dist_vu
            if dist_u < dist[u]:
                dist[u] = dist_u
                heappush(q, (dist_u, u))
    return dist


for a, b in L:
    graph[a-1].append((b-1, 1))
    graph[b-1].append((a-1, 1))

ans = 0
for a, b in L:
    E = deepcopy(graph)
    E[a-1].remove((b-1, 1))
    d = dijkstra(E, a-1)
    if d[b-1] == INF:
        ans += 1
print(ans)

Solution (Python):
import sys
N, M = map(int, sys.stdin.readline().rstrip().split(" "))
bridges = []
for i in range(M):
    a, b = map(int, sys.stdin.readline().rstrip().split(" "))
    a, b = a - 1, b - 1
    bridges.append((a,b))

par = []





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

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

def unite(x, y):
    tmpx = root(x)
    tmpy = root(y)

    if tmpx == tmpy:
        return

    
    
    

    par[tmpy] = tmpx

ans = 0
for i in range(M):
    par = [k for k in range(N)]
    for j, e in enumerate(bridges):
        if j == i:
            continue
        a, b = e
        unite(a, b)

    a, b = bridges[i]
    if not issame(a, b):
        ans += 1

print(ans)