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):
from collections import defaultdict

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

G = defaultdict(list)

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




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


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


print(cnt)

Solution (Python):


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

class UnionFind:

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

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

    def union(self, x, y):
        x_root = self.root(x)
        y_root = self.root(y)
        if x_root == y_root:
            pass
        else:
            self.parent[x_root] = y_root

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

ans = 0

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

for i in range(m):
    uf = UnionFind(n)
    for j in range(m):
        if i == j:
            continue
        a, b = input_[j]
        uf.union(a, b)
    for k in range(1, n):
        if not uf.same(0, k):
            ans += 1
            break
print(ans)

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

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

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

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

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

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

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

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

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            return self.find(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]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x
        if self.rank[x] == self.rank[y]:
            self.rank[x] += 1

N,M=list(map(int,input().split()))
S=set()
for _ in range(M):
    a,b=list(map(int,input().split()))
    a-=1
    b-=1
    S.add((a,b))

ct=0
for i in S:
    T=S-{i}
    uf=UnionFind(N)
    for (j,k) in T:
        uf.union(j,k)
    a=uf.find(0)
    for l in range(1,N):
        if a!=uf.find(l):
            ct+=1
            break
print(ct)

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

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

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

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

print(ans)

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

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

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

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

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

def union(a,b):
    a = root(a)
    b = root(b)
    if a == b:
        return False
    if size(a) < size(b):
        a,b = b,a
    par[a] += par[b]
    par[b] = a
    return True

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

Solution (Python):
class UnionFind():
    def __init__(self, n):
        self.parents = [-1 for _ in range(n)]  

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

    def merge(self, x, y):  
        x_root = self.root(x)  
        y_root = self.root(y)  

        if x_root == y_root:  
            return

        if abs(self.parents[x_root]) >= abs(self.parents[y_root]):  
            self.parents[x_root] += self.parents[y_root]
            self.parents[y_root] = x_root
        else:
            self.parents[y_root] += self.parents[x_root]
            self.parents[x_root] = y_root

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

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

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

    print(ans)


if __name__ == "__main__":
    main()

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

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

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

print(cnt)

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)
ab_list = []
ans =0
for i in range(M):
    a,b = map(int, input().split())
    a, b = a-1, b-1
    ab_list.append([a, b])

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

Solution (Python):
class UnionFind():
    """
    UnionFindTreeのクラス
    
    Attributes:
    n: int: ノード数
    parents: そのノードが属する木の根を格納, 根の場合は-1

    """
    def __init__(self, n):
        """ノード数nで初期化"""
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        """ノード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が属するグループと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):
        """xが属するグループの要素数を返す"""
        return -self.parents[self.find(x)]

    def same(self, x, y):
        """x, yが同じグループに属するかどうかを返す"""
        return self.find(x) == self.find(y)

    def members(self, x):
        """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):
        """{root: [そのグループの要素リスト]}の辞書を返す"""
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        """printデバッグ用. root: [要素リスト]をstrで返す"""
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

    
N, M = map(int, input().split())
from collections import defaultdict
E = []
for _ in range(M):
    a, b = map(lambda x: int(x)-1, input().split())
    E.append((a, b))

ans = 0
for bri in range(M):
    uf = UnionFind(N)
    for e in range(M):
        if e == bri:
            continue
        uf.union(*E[e])

    if uf.group_count() != 1:
        ans += 1
print(ans)

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

Solution (Python):
from collections import deque, defaultdict
import sys
sys.setrecursionlimit(2**20)
class LowLink:
    """
    与えられたグラフの関節点と橋を求める
    Attributes:
    size: グラフの頂点数
    pre: preorderでの訪問順
    low: 
        
        
    articulations<list>: 関節点のリスト
    bridges<list>: 橋のリスト

    """
    def __init__(self, v):
        self.size = len(v) + 1
        self.v = v
        self.pre = [None]*self.size
        self.low = [None]*self.size
        self.articulations = []
        self.bridges = []
        for x in range(self.size):
            if self.pre[x] is None:
                self.cnt = 0
                self.dfs(x, None)
    
    def dfs(self, x, prev):
        """
        DFSにより橋と関節点を求める
        x: 現在訪れているノード
        prev: ひとつ前のノード
        """
        self.pre[x] = self.low[x] = self.cnt 
        self.cnt += 1 
        is_articulation = False
        n = 0 
        for y in self.v[x]:
            if self.pre[y] is None: 
                n += 1 
                low_y = self.dfs(y, x) 
                if low_y < self.low[x]:
                    
                    self.low[x] = low_y
                if self.pre[x] <= low_y:
                    if self.pre[x]: 
                        is_articulation = True
                    if self.pre[x] < low_y:
                        self.bridges.append(
                            (min(x,y), max(x,y))
                        )
            else:
                if y != prev and self.pre[y] < self.low[x]:
                    
                    
                    self.low[x] = self.pre[y]
        
        if prev is None and n > 1:
            
            
            is_articulation = True
        
        if is_articulation:
            self.articulations.append(x)
        
        return self.low[x]

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

if __name__ == "__main__":
    solve()

Solution (Python):
from collections import deque, defaultdict
N, M = map(int, input().split())
adj = [[0]*(N+1) for _ in range(N+1)] 
edges = [tuple(map(int, input().split())) for _ in range(M)]
bridges = []
for e in edges:
    x,y=e
    adj[x][y] = 1
    adj[y][x] = 1

for bridge in edges:
    bx, by = bridge
    adj[bx][by] = 0
    adj[by][bx] = 0
    seen = [0]*(N+1)
    def dfs(s):
        seen[s] = 1
        for nx in range(1, N+1):
            if adj[s][nx]:
                if seen[nx]:
                    continue
                dfs(nx)
    dfs(1)
    is_ok = 1
    for i in range(1, N+1):
        if not seen[i]:
            is_ok = 0
            break
    if not is_ok:
        bridges.append(bridge)
    adj[bx][by] = 1
    adj[by][bx] = 1

print(len(bridges))

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

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

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

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

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

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

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


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

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

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

    print(count)

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

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

ans = 0

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

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

print(ans)

Solution (Python):
import sys


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

    def _root(self, x):
        stack = []
        tbl = self.table
        while tbl[x] >= 0:
            stack.append(x)
            x = tbl[x]
        for y in stack:
            tbl[y] = x
        return x

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

    def is_linked(self):
        if len(set([self._root(i) for i in range(len(self.table))])) <= 1:
            return True
        else:
            return False

    def union(self, x, y):
        r1 = self._root(x)
        r2 = self._root(y)
        if r1 == r2:
            return
        
        d1 = self.table[r1]
        d2 = self.table[r2]
        if d1 <= d2:
            self.table[r2] = r1
            if d1 == d2:
                self.table[r1] -= 1
        else:
            self.table[r1] = r2


def main():
    input = sys.stdin.buffer.readline
    n, m = map(int, input().split())
    edges = [tuple(map(lambda x: int(x) - 1, input().split())) for _ in range(m)]
    ans = 0
    for i in range(m):
        uf = UnionFind(n)
        for j in range(m):
            if j == i:
                continue
            uf.union(*edges[j])
        if not uf.is_linked():
            ans += 1
    print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
import copy

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

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


main()

Solution (Python):
class UnionFind:
    def __init__(self, n=0):
        self.d = [-1]*n
        self.u = n
    def root(self, x):
        if self.d[x] < 0:
            return x
        self.d[x] = self.root(self.d[x])
        return self.d[x]
    def unite(self, x, y):
        x, y = self.root(x), self.root(y)
        if x == y:
            return False
        if x > y:
            x, y = y, x
        self.d[x] += self.d[y]
        self.d[y] = x
        self.u -= 1
        return True
    def same(self, x, y):
        return self.root(x) == self.root(y)
    def size(self, x):
        return -self.d[self.root(x)]
    def num_union(self):
        return self.u


import sys
input = sys.stdin.buffer.readline
N, M = map(int, input().split())
E = [tuple(map(lambda x:int(x)-1, input().split())) for _ in range(M)]

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

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())
ab = [list(map(int,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:
            continue
        else:
            unite(ab[j][0]-1,ab[j][1]-1)
    
    if size(1)!=N:
        ans+=1

print(ans)

Solution (Python):
from collections import deque
number,m = map(int,input().split())

h = deque([])

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

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

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

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

        for n in g[now-1]:

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

print(count)

Solution (Python):
import networkx as nx

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

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

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

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

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

Solution (Python):
from collections import defaultdict
vis = [0 for i in range(0 , 2000)]
lt = [0 for i in range(0 , 2000)]
dis = [0 for i in range(0 , 2000)]
adj = defaultdict(list)
time = 0
ans = 0
def dfs(u , p):
	global time , ans
	time = time+1
	lt[u]= dis[u]=time
	vis[u]=1
	for v in adj[u]:
		if v==p:
			continue
		if vis[v]==0:
			dfs(v , u)
			lt[u]=min(lt[u] , lt[v])
			if lt[v]>dis[u]:
				ans = ans+1
		else:
			lt[u]=min(lt[u] , dis[v])
def main():
	n , m = map(int , input().split())
	for i in range(0 , m):
		u, v= map(int , input().split())
		adj[u].append((v))
		adj[v].append((u))
	dfs(1, 0)
	print(ans)
if __name__=="__main__":
	main()

Solution (Python):
from collections import defaultdict
vis = [0 for i in range(0 , 2000)]
lt = [0 for i in range(0 , 2000)]
dis = [0 for i in range(0 , 2000)]
adj = defaultdict(list)
time = 0
ans = 0
def dfs(u , p):
	global time , ans
	time = time+1
	lt[u]= dis[u]=time
	vis[u]=1
	for v in adj[u]:
		if v==p:
			continue
		if vis[v]==0:
			dfs(v , u)
			lt[u]=min(lt[u] , lt[v])
			if lt[v]>dis[u]:
				ans = ans+1
		else:
			lt[u]=min(lt[u] , dis[v])
def main():
	n , m = map(int , input().split())
	for i in range(0 , m):
		u, v= map(int , input().split())
		adj[u].append((v))
		adj[v].append((u))
	dfs(1, 0)
	print(ans)
if __name__=="__main__":
	main()

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

Solution (Python):
from collections import deque

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