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 heapq import heappush, heappop
from itertools import permutations, accumulate, combinations
import math
import bisect
import numpy as np
from collections import defaultdict, deque
import sys
input = sys.stdin.readline





def bfs(s, n, g):
    que = deque([])
    que.append(s)
    check = [-1] * n
    check[s] = 0
    while que:
        u = que.popleft()
        for v in g[u]:
            if check[v] == -1:
                check[v] = check[u] + 1
                que.append(v)
    if -1 in check:
        return True
    else:
        return False


def main():
    n, m = map(int, input().split())
    g = [[] for _ in range(n)]
    gg = deque([])
    for _ in range(m):
        a, b = [int(i) - 1 for i in input().split()]
        g[a].append(b)
        g[b].append(a)
        gg.append((a, b))
    ans = 0
    for i in range(m):
        a, b = gg.popleft()
        g[a].remove(b)
        g[b].remove(a)
        if bfs(0, n, g):
            ans += 1
        g[a].append(b)
        g[b].append(a)
    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 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())
bridges = []
ans = 0
for i in range(m):
    a,b = map(int,input().split())
    bridges.append((a-1,b-1))
for i in range(m):
    uf = UnionFind(n)
    for j in range(m):
        if j != i:
            a,b = bridges[j]
            uf.union(a,b)
    if uf.group_count() != 1:
        ans += 1
print(ans)

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

class UnionFind:
    def __init__(self, N):
        self.parent = list(range(N))
        self.rank = [0] * N
        self.size = [1] * N

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

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

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

    def get_size(self, x):
        return self.size[self.find(x)]

N, M = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(M)]
ans = 0
for i in range(M):
    uf = UnionFind(N+1)
    for j in range(M):
        if i == j:
            continue
        u, v = edges[j]
        uf.unite(u, v)
    u, v = edges[i]
    if uf.get_size(u) != N:
        ans += 1
print(ans)

Solution (Python):
import sys
input = sys.stdin.buffer.readline
n,m=map(int,input().split())
es=[list(map(int,input().split())) for _ in range(m)]
def check(s,t):
	q=[0]
	vis=[0]*n
	vis[0]=1
	while q:
		c=q.pop()
		for x in con[c]:
			if (c==s and x==t) or (c==t and x==s) or vis[x]:
				continue
			vis[x]=1
			q.append(x)
	return not all(vis)
con=[[] for _ in range(n)]
for s,t in es:
	con[s-1]+=t-1,
	con[t-1]+=s-1,
print(sum(check(s-1,t-1) for s,t in es))

Solution (Python):
n,m = map(int,input().split())
edge = []
bridge = []
for i in range(n+1):
    edge.append([])
for i in range(m):
    a,b = map(int,input().split())
    edge[a].append(b)
    edge[b].append(a)
    bridge.append((a,b))

def dfs(start, st, go):
    stack = [start]
    used = set()
    used.add(start)
    while stack:
        here = stack.pop()
        for i in edge[here]:
            if here == st and i == go:
                pass
            elif i == st and here == go:
                pass
            elif i not in used:
                stack.append(i)
                used.add(i)
    return used

ans = 0
for i in range(m):
    tar = bridge[i]
    used = dfs(1, tar[0], tar[1])
    if len(used) != n:
        ans += 1
print(ans)

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

def bfs(p):
  seen = [False for i in range(N+1)]
  l = [p]
  while len(l)>0:
    v = l.pop(0)
    for i in G[v]:
      if seen[i] == False:
        seen[i] = True
        l.append(i)
      else:
        continue  
  if sum(seen) != N:
    return 1
  else:
    return 0  

cnt = 0
for h in lh:
  a,b = h[0],h[1]
  G[a].remove(b)
  G[b].remove(a)
  cnt += bfs(1)
  G[a].append(b)
  G[b].append(a)
print(cnt)

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

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

ans = m
for i in range(m):
  union = UnionFind(n)
  for j in range(m):
    if i == j:
      continue
    union.union(node[j][0], node[j][1])
  key = True
  for j in range(n):
    for k in range(j+1, n):
      if union.same_check(j+1, k+1) == False:
        key = False
  if key:
    ans -= 1
print(ans)

Solution (Python):
def main():
    N, M = (int(i) for i in input().split())
    edge = [[] for _ in range(N)]
    edge_list = []
    for i in range(M):
        a, b = (int(i) for i in input().split())
        edge[a-1].append(b-1)
        edge[b-1].append(a-1)
        edge_list.append((a-1, b-1))

    def dfs(G, v, e):
        seen = [False]*N
        todo = []
        seen[v] = True
        todo.append(v)
        while todo:
            u = todo.pop()
            for next_v in G[u]:
                if seen[next_v]:
                    continue
                if (u, next_v) == e or (next_v, u) == e:
                    continue
                seen[next_v] = True
                todo.append(next_v)
        return all(seen)

    ans = 0
    for e in edge_list:
        if dfs(edge, 0, e):
            pass
        else:
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
from collections import Counter,defaultdict,deque
from heapq import heappop,heappush,heapify
import sys,bisect,math,itertools,fractions,pprint
sys.setrecursionlimit(10**8)
mod = 10**9+7
INF = float('inf')
def inp(): return int(sys.stdin.readline())
def inpl(): return list(map(int, sys.stdin.readline().split()))

n,m = inpl()
g = [[] for _ in range(n)]
r = dict()
cnt = 0
for _ in range(m):
    a,b = inpl()
    g[a-1].append(b-1)
    g[b-1].append(a-1)
    r[cnt] = (a-1,b-1)
    cnt += 1
res = 0
def chk(g):
    seen = [False] * n
    seen[0] = True
    q = deque([0])
    while q:
        v = q.popleft()
        for nv in g[v]:
            if seen[nv]:
                continue
            seen[nv] = True
            q.append(nv)
    if sum(seen) == n:
        return True
    return False
for i in range(m):
    gg = [[] for _ in range(n)]
    a,b = r[i]
    for j in range(n):
        for k in g[j]:
            if (j,k) == (a,b) or (j,k) == (b,a):
                continue
            gg[j].append(k)
    if not chk(gg):
        res += 1
print(res)

Solution (Python):
def dfs(G,v,N):
    seen[v]=True
    for nv in G[v]:
        if(seen[nv]):
            continue
        dfs(G,nv,N)

N,M=map(int,input().split())
xy=[list(map(lambda x:int(x)-1,input().split())) for i in range(M)]
res=0
for i in range(M):
    G=[[] for i in range(N)]
    seen=[False]*N
    for j in range(M):
        if(i==j):
            continue
        G[xy[j][0]].append(xy[j][1])
        G[xy[j][1]].append(xy[j][0])
    cnt=0
    for k in range(N):
        if(not seen[k]):
            dfs(G,k,N)
            cnt+=1
    if(cnt>1):
        res+=1
print(res)

Solution (Python):
from collections import deque


def main():
    n, m = map(int, input().split())
    g = [[] for _ in range(n)]
    edge = []
    answer = 0
    for _ in range(m):
        a, b = map(lambda x: int(x) - 1, input().split())
        g[a].append(b)
        g[b].append(a)
        edge.append([a, b])
    for ng in edge:
        ng.sort()
        visited = [0 for _ in range(n)]
        q = deque([0])
        while q:
            now = q.pop()
            if visited[now] == 0:
                visited[now] = 1
                for next_v in g[now]:
                    if ng != sorted([next_v, now]):
                        q.append(next_v)
        if sum(visited) < n:
            answer += 1
    print(answer)


if __name__ == '__main__':
    main()

Solution (Python):

class UnionFind :
    def __init__(self, size) :
        self.parent = list(range(size))
        self.height = [0] * size
        self.size = [1] * size
        self.component = size

    def root(self, index) :
        if self.parent[index] == index :  
            return index
        rootIndex = self.root(self.parent[index])  
        self.parent[index] = rootIndex  
        return rootIndex

    def union(self, index1, index2) :  
        root1 = self.root(index1)
        root2 = self.root(index2)

        if root1 == root2 :  
            return

        self.component -= 1  

        if self.height[root1] < self.height[root2] :
            self.parent[root1] = root2  
            self.size[root2] += self.size[root1]
        else :
            self.parent[root2] = root1  
            self.size[root1] += self.size[root2]
            if self.height[root1] == self.height[root2] :
                self.height[root1] += 1
        return

    def isSameRoot(self, index1, index2) :
        return self.root(index1) == self.root(index2)

    def sizeOfSameRoot(self, index) :
        return self.size[self.root(index)]

    def getComponent(self) :
        return self.component

N, M = map(int, input().split())
AB = [tuple(map(lambda a: int(a) - 1, input().split())) for _ in range(M)]

ans = 0
for i in range(M):
    tree = UnionFind(N)
    for a, b in (AB[:i] + AB[i + 1:]):
        tree.union(a, b)
    if tree.getComponent() > 1:
        ans += 1
print(ans)

Solution (Python):
n, m = map(int, input().split())
chk = []
for i in range(m):
    u, v = map(int, input().split())
    u -= 1
    v -= 1
    chk.append((u,v))
chk = tuple(chk)

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 size(x):
    return -par[find(x)]

ans = 0
for i in range(m):
  par = [-1]*n
  for j in range(m):
    if i == j:
      continue
    else:
      unite(chk[j][0],chk[j][1])
  if size(0) != n:
    ans += 1
    
print(ans)

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

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

    def unite(self,x,y): 
        return self.link(self.findSet(x), self.findSet(y))

    def link(self,x,y):
        if self.rank[x] > self.rank[y]: 
            self.parent[y] = x
        else:
            self.parent[x] = y
            if self.rank[x] == self.rank[y]: self.rank[y] += 1

    def findSet(self,x):
        if x != self.parent[x]: 
            self.parent[x] = self.findSet(self.parent[x])
        return self.parent[x]

n,m = map(int,input().split())
ans = 0
edge = [[int(i)-1 for i in input().split()] for _ in range(m)]
for i in range(m):
    ds = DisjointSet(n)
    for j in range(m):
        if j == i: continue
        a,b = edge[j]
        ds.unite(a,b)
    for j in range(1,n):
        if not ds.same(0,j):
            ans += 1
            break
        
print(ans)

Solution (Python):
from collections import deque
n,m = map(int,input().split())
to = [[] for _ in range(n)]
e = []
for _ in range(m):
    a,b = map(int,input().split())
    a -= 1
    b -= 1
    to[a].append(b)
    to[b].append(a)
    e.append((a,b))
ans = m
seen = [False]*n
q = deque()
for i in range(m):
    a,b = e[i]
    q.clear()
    q.append((a,-1))
    for j in range(n): seen[j] = False
    flag = True
    while q and flag:
        cur,prev = q.popleft()
        seen[cur] = True
        for nxt in to[cur]:
            if nxt == b:
                if cur == a: continue
                ans -= 1
                flag = False
                break
            if nxt == prev: continue
            if seen[nxt]: continue
            q.append((nxt,cur))
print(ans)

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





def bfs(s, n, g):
    dist = [-1] * n
    dist[s] = 0
    que = deque([])
    que.append(s)
    while que:
        v = que.popleft()
        for nv in g[v]:
            if dist[nv] != -1:
                continue  
            dist[nv] = dist[v] + 1
            que.append(nv)
    if -1 in dist:
        return True
    else:
        return False


def main():
    n, m = map(int, input().split())
    g = [[] for _ in range(n)]
    gg = []
    for _ in range(m):
        a, b = [int(i) - 1 for i in input().split()]
        g[a].append(b)
        g[b].append(a)
        gg.append((a, b))
    ans = 0
    for a, b in gg:
        g[a].remove(b)
        g[b].remove(a)
        if bfs(0, n, g):
            ans += 1
        g[a].append(b)
        g[b].append(a)
    print(ans)
    return


if __name__ == "__main__":
    main()

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


def bfs(s, n, g):
    dist = [-1] * n
    dist[s] = 0
    que = deque([])
    que.append(s)
    while que:
        v = que.popleft()
        for nv in g[v]:
            if dist[nv] != -1:
                continue
            dist[nv] = dist[v] + 1
            que.append(nv)
    if -1 in dist:
        return True
    else:
        return False


def main():
    n, m = map(int, input().split())
    g = [[] for _ in range(n)]
    gg = []
    for _ in range(m):
        a, b = [int(i) - 1 for i in input().split()]
        g[a].append(b)
        g[b].append(a)
        gg.append((a, b))
    ans = 0
    for a, b in gg:
        g[a].remove(b)
        g[b].remove(a)
        if bfs(0, n, g):
            ans += 1
        g[a].append(b)
        g[b].append(a)
    print(ans)
    return


if __name__ == "__main__":
    main()

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


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 i in range(m)]
ans=0
for i in range(m):
    uf=UnionFind(n)
    for j in range(m):
        if j==i:
            continue
        else:
            uf.union(a[j][0]-1,a[j][1]-1)
    if not uf.same(a[i][0]-1,a[i][1]-1):
        ans+=1
print(ans)

Solution (Python):
n,m = map(int, input().split())
ab = [list(map(int, input().split())) for i in range(m)]
ans = 0
for i in range(m):
  graph = [list() for i in range(n+1)]
  visited = [True]+[False] * (n)
  for k,(a,b) in enumerate(ab):
    if k == i:
      continue
    graph[a].append(b)
    graph[b].append(a)
  NEXT = [1]
  while len(NEXT):
    now = NEXT.pop()
    for j in graph[now]:
      if not visited[j]:
        visited[j] = True
        NEXT.append(j)
  if not all([j for j in visited]):
    ans += 1
print(ans)

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 heapq import heapify, heappop, 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

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


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

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

ans = 0

for i in range(M):
    a, b = L[i]
    E = deepcopy(graph)
    E[a-1].remove((b-1, 1))
    E[b-1].remove((a-1, 1))
    dist = dijkstra(E, 0)
    if dist.count(INF) > 0:
        ans += 1

print(ans)

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

graph = [[False] * N for _ in range(N)]
for a, b in X:
    graph[a - 1][b - 1] = True
    graph[b - 1][a - 1] = True


def dfs(u):
    visited[u] = True
    for v in range(N):
        if visited[v] or not graph[u][v]:
            continue
        dfs(v)


res = 0
for i in range(M):
    a, b = X[i]
    a -= 1
    b -= 1
    
    graph[a][b] = False
    graph[b][a] = False
    
    visited = [False] * N
    dfs(0)
    res += int(not all(visited))
    
    graph[a][b] = True
    graph[b][a] = True
    
print(res)

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

def find(x):
    if par[x] == x:
        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
    
    if rank[x] < rank[y]:
        par[x] = y
    else:
        par[y] = x
        if rank[x] == rank[y]:
            rank[x] += 1

cnt = 0
for i in range(M):
    par = list(range(N + 1))
    rank = [0] * (N + 1)
    for j, (u, v) in enumerate(X):
        if i == j:
            continue
        unite(u, v)
    
    res = True
    for j in range(1, N + 1):
        for k in range(1, N + 1):
            res &= find(j) == find(k)

    cnt += int(not res)
        
print(cnt)

Solution (Python):
n,m = map(int,input().split())
links = [set() for i in range(n)]
for i in range(m):
	a,b = [int(i)-1 for i in input().split()]
	links[a].add(b)
	links[b].add(a)

ans = 0
pre = [-1]*n
low = [-1]*n
 
def dfs(v,p,a):
	global ans
	if pre[v] != -1:
		low[a] = min(low[a],low[v])
		return low[a]
	pre[v] = p
	low[v] = p
	for u in links[v]:
		if u == a:
			continue
		low[v] = min(low[v],dfs(u,p+1,v))
	if pre[v] == low[v]:
		ans += 1
	return low[v]
 
dfs(0,0,None)
print(ans-1)

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 unite(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())
A=[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: 
            uf.unite(A[j][0],A[j][1])
    f = 1
    g = uf.find(1) 
    for j in range(1,n+1):
        if g != uf.find(j): 
            f = 0
            break
    if not f:
        ans += 1
print(ans)

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 heapify, heappop, 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)]

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

graph = defaultdict(list)
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))
    E[b-1].remove((a-1, 1))
    d = dijkstra(E, a-1)
    if d[b-1] == INF:
        ans += 1
print(ans)

Solution (Python):
from scipy.sparse.csgraph import dijkstra
N,M = map(int,input().split())
edge = [[int(x) for x in input().split()] for _ in range(M)]

graph = [[0]*(N+1) for _ in range(N+1)]

for a,b in edge:
    graph[a][b] = 1
    
answer = 0
INF = 10 ** 9
for a,b in edge:
    graph[a][b] = INF
    
    
    
    dist = dijkstra(graph, indices = a, directed = False)
    if dist[b] >= INF:
        answer += 1
    graph[a][b] = 1
 
print(answer)

Solution (Python):
import sys

n, m, *ab = map(int, sys.stdin.read().split())
graph = [set() for _  in range(n)]
for a, b in zip(*[iter(ab)] * 2):
    a -= 1; b -= 1
    graph[a].add(b); graph[b].add(a)

def main():
    stack = [i for i in range(n) if len(graph[i]) == 1]
    bridges = 0
    while stack:
        x = stack.pop()
        if not graph[x]: continue
        y = graph[x].pop()
        graph[y].remove(x)
        bridges += 1
        if len(graph[y]) == 1:
            stack.append(y)
    print(bridges)

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

Solution (Python):
import math,itertools,fractions,heapq,collections,bisect,sys,queue,copy

sys.setrecursionlimit(10**7)
inf=10**20
mod=10**9+7
dd=[(-1,0),(0,1),(1,0),(0,-1)]
ddn=[(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def LS(): return sys.stdin.readline().split()
def S(): return input()

limit=50
graph=[[False]*limit for _ in range(limit)]
visited=[False]*limit

def dfs(n,v):
  visited[v]=True
  for v2 in range(n):
    if graph[v][v2]==False:
      continue
    if visited[v2]:
      continue
    dfs(n,v2)

def main():
  n,m=LI()
  a=[[] for _ in range(n*n)]
  b=[[] for _ in range(n*n)]
  for i in range(m):
    _a,_b=LI()
    _a-=1
    _b-=1
    a[i]=_a
    b[i]=_b
    graph[_a][_b]=True
    graph[_b][_a]=True

  ans=0
  for i in range(m):
    graph[a[i]][b[i]]=False
    graph[b[i]][a[i]]=False

    for j in range(n):
      visited[j]=False
    dfs(n,0)
    no_visited=False
    for j in range(n):
      if visited[j]==False:
        no_visited=True
    if no_visited:
      ans+=1
    graph[a[i]][b[i]]=True
    graph[b[i]][a[i]]=True

  return ans


print(main())

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

import sys
sys.setrecursionlimit(10**8)

def dfs(v, es):
    
    if len(es[v])==0:
        return 0
    for u in es[v]:
        if visited[u]==False:
            visited[u]=True
            dfs(u,es)
    return 0

import copy
ans = 0
for i in range(M):
    visited = [False]*N
    a,b = edges[i]
    es = copy.deepcopy(edge)
    
    es[a].remove(b)
    es[b].remove(a)
    for v in range(N):
        if visited[v]==False:
            visited[v]=True
            dfs(v,es)
            if False in visited:
                
                break
    else:
        continue
    ans += 1
print(ans)

Solution (Python):
n, m = map(int, input().split())
list_AB = [ list(map(int,input().split(" "))) for i in range(m)]
ans = 0

def dfs(n, point):
    for m in L[n]:
        if point[m] == 1:
            continue
        else:
            point[m] = 1
            dfs(m, point)

for i in range(m):
    L = [[] for _ in range(n + 1)]
    point = [0]*(n+1)

    for j in range(len(list_AB)):
        a = list_AB[j][0]
        b = list_AB[j][1]
        if i != j:
            L[a].append(b)
            L[b].append(a)
    point[1] = 1
    dfs(1, point)

    if sum(point) != n:
        ans += 1

print(ans)

Solution (Python):
from collections import Counter

maxn = 100000

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

par = [0] * n
rank = [0] * n


for i in range(n):
    par[i] = i
    rank[i] = 0


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

def unite(x , y):
    rx = find(x)
    ry = find(y)
    
    if rx == ry:
        return
    
    if rank[rx] < rank[ry]:
        par[rx] = ry
    elif rank[rx] > rank[ry]:
        par[ry] = rx
    else:
        par[ry] = x
        rank[rx] += 1

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):
    for j in range(n):
        par[j] = j
        rank[j] = 0
        
    for j in range(m):
        if i == j:
            continue
        unite(a[j],b[j])
        
    l = [find(k) for k in range(n)]
    fl = 1
    
    for j in range(n-1):
        if l[j] != l[j+1]:
            fl = 0
            
    if fl == 0:
        ans += 1
        
print(ans)