Problem:
 Score : 300 points    Problem Statement You are given an undirected connected graph with N vertices and M edges that does not contain self-loops and double edges. The i -th edge (1 \leq i \leq M) connects Vertex a_i and Vertex b_i .  An edge whose removal disconnects the graph is called a bridge . Find the number of the edges that are bridges among the M edges.      Notes  A self-loop is an edge i such that a_i=b_i  (1 \leq i \leq M) .  Double edges are a pair of edges i,j such that a_i=a_j and b_i=b_j  (1 \leq i<j \leq M) .  An undirected graph is said to be connected when there exists a path between every pair of vertices.       Constraints  2 \leq N \leq 50  N-1 \leq M \leq min(N(N−1)⁄2,50)  1 \leq a_i<b_i \leq N  The given graph does not contain self-loops and double edges.  The given graph is connected.         Input Input is given from Standard Input in the following format:  N  M  a_1  b_1  a_2  b_2  :  a_M  b_M       Output Print the number of the edges that are bridges among the M edges.        Sample Input 1 7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7      Sample Output 1 4  The figure below shows the given graph:     The edges shown in red are bridges. There are four of them.       Sample Input 2 3 3
1 2
1 3
2 3      Sample Output 2 0  It is possible that there is no bridge.       Sample Input 3 6 5
1 2
2 3
3 4
4 5
5 6      Sample Output 3 5  It is possible that every edge is a bridge.

Solution (Python):
def LowLink(Graph, N):
    def dfs(v, k, prev):
        used[v] = True
        order[v] = k
        low[v] = order[v]
        k += 1
        is_aps = False
        count = 0
        for w in Graph[v]:
            if not used[w]:
                count += 1
                k = dfs(w, k, v)
                low[v] = min(low[v], low[w])
                if prev != -1 and order[v] <= low[w]:
                    is_aps = True
                if order[v] < low[w]:
                    bridges.append([min(v, w), max(v, w)])
            elif w != prev:
                low[v] = min(low[v], order[w])
        if prev == -1 and count >= 2:
            is_aps = True
        if is_aps:
            aps.append(v)
        return k
    
    used = [False] * N
    order = [0] * N
    low = [0] * N
    aps = []
    bridges = []
    k = 0
    for i in range(N):
        if not used[i]:
            k = dfs(i, k, -1)
    aps.sort()
    bridges.sort()
    
    return aps, bridges


N, M = map(int,input().split())
G = [[] for _ in range(N)]
for _ in range(M):
    a, b = map(int,input().split())
    G[a-1].append(b-1)
    G[b-1].append(a-1)
aps, bridges = LowLink(G, N)
print(len(bridges))

Solution (Python):
import sys

readline = sys.stdin.readline
MOD = 10 ** 9 + 7
INF = float('INF')
sys.setrecursionlimit(10 ** 5)


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

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

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

        if x == y:
            return

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

        self.parents[x] += self.parents[y]
        self.parents[y] = x

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

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

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

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

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

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


def main():
    n, m = list(map(int, readline().split()))
    edge = [list(map(int, readline().split())) for _ in range(m)]

    ans = 0
    for i in range(m):
        uf = UnionFind(n)
        for j in range(i):
            a = edge[j][0] - 1
            b = edge[j][1] - 1
            uf.union(a, b)
        for j in range(i+1,m):
            a = edge[j][0] - 1
            b = edge[j][1] - 1
            uf.union(a, b)
        if uf.group_count() != 1:
            ans += 1

    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
import sys
import string
import io

readline = sys.stdin.buffer.readline
n, m = map(int, readline().split())
es = []
for _ in range(m):
    a, b = map(int, readline().split())
    es.append((a, b))
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
ans = 0
for i in range(m):
    par = [_ for _ in range(n + 1)]
    for j, k in enumerate(es):
        if i == j:
            continue
        a, b = k
        unite(a, b)
    a, b = es[i]
    if not same(a, b):
        ans += 1
print(ans)

Solution (Python):
from collections import deque
N,M=map(int,input().split())
tree=[[] for _ in range(N)]
paths=[]
cnt=0
for i in range(M):
    a,b=map(int,input().split())
    tree[a-1].append(b-1)
    tree[b-1].append(a-1)
    paths.append([a-1,b-1])

for i in range(M):
    stop=paths[i]
    seen=[0]*N
    d=deque()
    d.append(0)
    while len(d)>0:
        v=d.popleft()
        seen[v]=1
        for j in tree[v]:
            if not(((v==stop[0])and(j==stop[1]))or((v==stop[1])and(j==stop[0])))and(seen[j]==0):
                d.append(j)
        
        
    if sum(seen)!=N:
        cnt=cnt+1
print(cnt)

Solution (Python):
def dfs(v):
    visited[v]=True
    for nv in range(n):
        if G[v][nv]==False:continue
        if visited[nv]:continue
        dfs(nv)

n,m=map(int,input().split())
G=[[False]*n for _ in range(n)]
ans=0
visited=[False for _ in range(n)]
A,B=[],[]
for i in range(m):
    a,b = map(int,input().split())
    A.append(b-1)
    B.append(a-1)
    G[a-1][b-1]=G[b-1][a-1]=True

for i in range(m):
    G[A[i]][B[i]]=G[B[i]][A[i]]=False
    visited = [False for _ in range(n)]
    dfs(0)
    if all(visited):
        ans += 1
    G[A[i]][B[i]]=G[B[i]][A[i]]=True

print(m-ans)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
import bisect 





import heapq
def dijkstra_heap(s, edge):
    
    
    
    d = [float("inf")] * N      
    used = [True] * N           
    d[s] = 0                    
    used[s] = False
    edgelist = []
    for e in edge[s]:
        heapq.heappush(edgelist, e)         
    while len(edgelist):
        minedge = heapq.heappop(edgelist)   
        
        if not used[minedge[1]]:            
            continue
        v = minedge[1]  
        d[v] = minedge[0]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                if e[0]+d[v] > d[e[1]]:                     
                    continue
                heapq.heappush(edgelist, [e[0]+d[v], e[1]]) 
    return d

N, M = mi()
memo = []
rel = [[] for i in range(N)]

for i in range(M):
    s, t = mi()
    s, t = s-1, t-1
    memo.append((s, t))
    rel[s].append([1, t])
    rel[t].append([1, s])

cnt = 0
for x in range(M):
    s, t = memo[x][0], memo[x][1]
    rel[s].remove([1, t])
    rel[t].remove([1, s])

    l = sorted(dijkstra_heap(0, rel))
    ind = bisect.bisect_left(l, float('inf'))
    if ind != N:
        cnt += 1

    rel[s].append([1, t])
    rel[t].append([1, s])

print(cnt)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]






from collections import deque
N, M = mi()
memo = []
rel = [[] for i in range(N)]

for i in range(M):
    s, t = mi()
    s, t = s-1, t-1
    memo.append((s, t))
    rel[s].append(t)
    rel[t].append(s)

cnt = 0
que = deque()
for x in range(M):
    s, t = memo[x][0], memo[x][1]
    rel[s].remove(t)
    rel[t].remove(s)

    que.append(0)
    used = [0]*N
    while que != deque():
        v = que.popleft()
        for nv in rel[v]:
            if not used[nv]:
                used[nv] = 1
                que.append(nv)
    if sum(used) != N:
        cnt += 1

    rel[s].append(t)
    rel[t].append(s)

print(cnt)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]






N, M = mi()
memo = []
rel = [[] for i in range(N)]

for i in range(M):
    s, t = mi()
    s, t = s-1, t-1
    memo.append((s, t))
    rel[s].append(t)
    rel[t].append(s)

def dfs(v):
    for nv in rel[v]:
        if not used[nv]:
            used[nv] = 1
            dfs(nv)
            if sum(used) == N:
                global flag
                flag = 1
                return

cnt = M
for x in range(M):
    s, t = memo[x][0], memo[x][1]
    rel[s].remove(t)
    rel[t].remove(s)
    flag = 0
    used = [0]*N
    dfs(0)
    if flag:
        cnt -= 1
    rel[s].append(t)
    rel[t].append(s)

print(cnt)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]






N, M = mi()
memo = []
rel = [[] for i in range(N)]


for i in range(M):
    s, t = mi()
    s, t = s-1, t-1
    memo.append((s, t))
    rel[s].append(t)
    rel[t].append(s)
    


def dfs(v):
    
    for nv in rel[v]:
    
        if not used[nv]:
        
            used[nv] = 1
            dfs(nv)
            if sum(used) == N:
                global flag
                flag = True
                return
            

cnt = M
for x in range(M):
    s, t = memo[x][0], memo[x][1]
    rel[s].remove(t)
    rel[t].remove(s)
    
    
    
    
    for i in range(N):
        
        flag = 0
        used = [0]*N
        used[i] = 1
        dfs(i)
        
        if flag:
            cnt -= 1
            break
    rel[s].append(t)
    rel[t].append(s)
    

print(cnt)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]



import copy
N, M = mi()
D = dp2(float('inf'), N, N)
memo = []
cnt = 0

for i in range(M):
    s, t = mi()
    s, t = s-1, t-1
    memo.append((s, t))
    D[s][t] = D[t][s] = 1

for x in range(M):
    d = copy.deepcopy(D)
    s, t = memo[x][0], memo[x][1]
    d[s][t] = d[t][s] = float('inf')
    for k in range(N):
        for i in range(N):
            for j in range(N):
                d[i][j] = min(d[i][j], d[i][k] + d[k][j])

    for i in range(N):
        for j in range(i+1, N):
            if d[i][j] == float('inf'):
                cnt += 1
                break
        else:
            continue
        break

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

ab_copy = [ab[i] for i in range(M)]
ans = 0
for i in range(M):
    ab_copy.pop(i)
    uf = UnionFind(N)
    for j in range(M-1):
        uf.union(ab_copy[j][0]-1,ab_copy[j][1]-1)
    if len(uf.roots())!=1:
        ans += 1
    ab_copy = [ab[i] for i in range(M)]
print(ans)

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]




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

N, M = mi()
ab = li2(M)
cnt = M

for i in range(M):
    T = UnionFind(N)
    for j in range(M):
        if i != j:
            a, b = ab[j][0]-1, ab[j][1]-1
            if not T.same(a, b):
                T.unite(a, b)
    for k in range(N):
        if T.size(k) != N:
            break
    else:
        cnt -= 1

print(cnt)

Solution (Python):
import copy

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

seen = [0] * n 

def dfs(g, s, t): 
    seen = [0] * n
    todo = [s]
    while(todo != []):
        v = todo.pop(len(todo)-1) 
        seen[v] = 1
        for i in g[v]:
            if seen[i] == 0:
                todo.append(i)
    return seen[t]

ans = 0
for i in range(m):
    H = copy.deepcopy(G)
    H[a[i]-1].remove(b[i]-1)
    H[b[i]-1].remove(a[i]-1)
    ans += 1-dfs(H, a[i]-1, b[i]-1)

print(ans)

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

def reach(s, g, visited):
    for i in range(N):
        if not linked[s][i]:
            continue
        if i == g:
            return True
        if i not in visited:
            if reach(i, g, visited | {i}):
                return True
    return False

cnt = 0
for i in range(M):
    a, b = edges[i]
    linked[a][b] = linked[b][a] = False
    if not reach(a, b, {a}):
        cnt += 1
    linked[a][b] = linked[b][a] = True
print(cnt)

Solution (Python):
n,m=map(int,input().split())
ab=[list(map(int,input().split())) for _ in range(m)]
graph=[[0 for _ in range(n)] for _ in range(n)]
for i in range(m):
  graph[ab[i][0]-1][ab[i][1]-1]=1
  graph[ab[i][1]-1][ab[i][0]-1]=1
visited=[0 for _ in range(n)]

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

ans=0

for i in range(m):
  graph[ab[i][0]-1][ab[i][1]-1]=0
  graph[ab[i][1]-1][ab[i][0]-1]=0
  for j in range(n):
    visited[j]=0
  dfs(0)
  bridge=0
  for j in range(n):
    if visited[j]==0:
      bridge=1
  if bridge==1:
    ans+=1
  graph[ab[i][0]-1][ab[i][1]-1]=1
  graph[ab[i][1]-1][ab[i][0]-1]=1
print(ans)

Solution (Python):
def main():
    from collections import deque

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

    g = tuple(set() for _ in range(N))
    es = []
    for _ in range(M):
        a, b = (int(x) - 1 for x in input().split())
        g[a].add(b)
        g[b].add(a)
        es.append((a, b))

    cnt = 0
    for e in es:
        v = 0

        dq = deque()
        dq.append(v)
        used = [False] * N
        used[v] = True

        while dq:
            v = dq.popleft()
            for u in g[v]:
                if used[u]: continue
                if (v, u) == e or (u, v) == e: continue
                used[u] = True
                dq.append(u)

        if all(used): continue
        cnt += 1

    print(cnt)


if __name__ == '__main__':
    main()

Solution (Python):
n,m = map(int,input().split())
a=[]
b=[]
vector=[[False for i in range(n)] for j in range(n)]

visited = [False]*n
for i in range(m):
  x,y=map(int,input().split())
  a.append(x-1)
  b.append(y-1)
  vector[x-1][y-1]=vector[y-1][x-1]=True
  


def dfs(v):
  visited[v]=True
  for i in range(n):
    if not vector[v][i]:continue
    if visited[i]:continue
    dfs(i)
      
def main():
  ans=0
  for i in range(m):
    vector[a[i]][b[i]]=vector[b[i]][a[i]]=False
  
    for j in range(n):visited[j]=False
   
    dfs(0)
    
    bridge=False
    for j in range(1,n):
      if visited[j]==False:
        bridge=True
    if bridge:
      ans+=1
    vector[a[i]][b[i]]=vector[b[i]][a[i]]=True
    
  print(ans)

if __name__=='__main__':
  main()

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
sys.setrecursionlimit(10 ** 6)

INF = float("inf")


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

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

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

        if x == y:
            return

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

        self.parents[x] += self.parents[y]
        self.parents[y] = x

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

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

    def members(self, x):  
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):  
        return [i for i, x in enumerate(self.parents) if x < 0]

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

    def all_group_members(self):  
        return {r: self.members(r) for r in self.roots()}

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


def main():
    N, M = map(int, input().split())
    uf = UnionFind(N)
    edge = []
    for _ in range(M):
        a, b = [int(i) - 1 for i in input().split()]
        edge.append((a, b))
        uf.union(a, b)
    ans = 0
    for i in range(M):
        new_uf = UnionFind(N)
        for j in range(M):
            a, b = edge[j]
            if i != j:
                new_uf.union(a, b)
        if new_uf.group_count() > 1:
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()

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
sys.setrecursionlimit(10**6)

INF = float("inf")


def dijkstra(s, n, graph):
    dist = [INF] * n
    visited = [False] * n
    dist[s] = 0
    hq = [(0, s)]  
    while hq:
        di, pi = heappop(hq)
        visited[pi] = True
        for dj, pj in graph[pi]:
            if visited[pj]:
                continue
            if dist[pj] > di + dj:
                dist[pj] = di + dj
                heappush(hq, (dist[pj], pj))
    return dist


def main():
    N, M = map(int, input().split())
    graph = [[] for _ in range(N)]
    edge = []
    for _ in range(M):
        a, b = map(int, input().split())
        a, b = a - 1, b - 1
        graph[a].append((1, b))
        graph[b].append((1, a))
        edge.append((a, b))
    cnt = 0
    for a, b in edge:
        graph[a].remove((1, b))
        graph[b].remove((1, a))
        d = dijkstra(0, N, graph)
        if INF in d:
            cnt += 1
        graph[b].append((1, a))
        graph[a].append((1, b))
    print(cnt)


if __name__ == '__main__':
    main()

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




def dfs(start, a, b, visited, n, graph):
    for node in graph[start]:
        if node not in visited:
            if (start, node) == (a, b) or (start, node) == (b, a):
                continue  
            else:
                visited.append(node)
                dfs(node, a, b, visited, n, graph)
    if len(visited) == n:
        return 0
    else:
        return 1


def main():
    N, M = map(int, input().split())
    graph = [[] for _ in range(N)]
    edge = []
    for _ in range(M):
        a, b = map(int, input().split())
        a, b = a - 1, b - 1
        graph[a].append(b)
        graph[b].append(a)
        edge.append((a, b))
    cnt = 0
    for a, b in edge:
        cnt += dfs(0, a, b, [], N, graph)
    print(cnt)


if __name__ == '__main__':
    main()

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

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

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

cnt = 0


def dfs(start, a, b, explored, n):
    for node in graph[start]:
        if node not in explored:
            if (start, node) == (a, b) or (start, node) == (b, a):
                continue
            else:
                explored.append(node)
                dfs(node, a, b, explored, n)
    if len(explored) == n:
        return 0
    else:
        return 1
x = 0
for i, j in edge:
    x += dfs(0, i, j, [], n)


print(x)

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

for i in range(M):
  a,b=map(int, input().split())
  G[a-1].append((i,b-1))
  G[b-1].append((i,a-1))
  
L=[-1]*M
def dfs(start,goal,pre,num):
  if start==goal:
    return False
  done[start]=1
  for i,next_node in G[start]:
    if next_node==pre or i==num or done[next_node]==1:
      continue
    if not dfs(next_node,goal,start,num):
      return False
  return True

for a in range(N):
  for t in G[a]:
    i,b=t
    done=[0]*N
    if L[i]==-1:
      
      if dfs(a,b,-1,i):
        L[i]=1
      else:
        L[i]=0
print(sum(L))

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

par=[0]*(N+1)

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

ret=0

for i in range(M):
    par=list(range(N+1))

    for j in range(M):
        if i==j:
            continue
        a,b=g[j]

        unite(a,b)
    
    for j in range(1,N+1):
        if not same(1,j):
            ret+=1
            break
    

print(ret)

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

from collections import deque

def bfs(s, es):
    visited=[0]*n
    visited[s]=1
    q=deque([s])
    while q:
        p=q.pop()
        for r in es[p]:
            if visited[r]==0:
                q.append(r)
                visited[r]=1
    if 0 in visited:
        return False
    else: return True

from copy import deepcopy
ans=0
for e in es0:
    newes=deepcopy(es)
    newes[e[0]].remove(e[1])
    newes[e[1]].remove(e[0])
    if bfs(0,newes):
        continue
    else:
        ans+=1
print(ans)

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

from collections import deque

def bfs(s, es):
    visited=[0]*n
    visited[s]=1
    q=deque([s])
    while q:
        p=q.popleft()
        for r in es[p]:
            if visited[r]==0:
                q.append(r)
                visited[r]=1
    if 0 in visited:
        return False
    else: return True

from copy import deepcopy
ans=0
for e in es0:
    newes=deepcopy(es)
    newes[e[0]].remove(e[1])
    newes[e[1]].remove(e[0])
    if bfs(0,newes):
        continue
    else:
        ans+=1
print(ans)

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

def dfs(v, prohibited):
    global visited
    visited[v] = True
    for adj in V[v]:
        if {v, adj} == {lst[prohibited][0], lst[prohibited][1]}: continue
        if visited[adj]: continue
        dfs(adj, prohibited)

ans = 0


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

print(ans)

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

n, m = map(int, input().split())
graph = [[False] * n for _ in range(n)] 
sides = []

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

ans = 0
for side in sides:
    visited = [False] * n
    l, r = side
    graph[l][r] = False
    graph[r][l] = False
    dfs(0)
    if False in visited:
        ans += 1
    graph[l][r] = True
    graph[r][l] = True

print(ans)

Solution (Python):
from sys import stdin,setrecursionlimit
from copy import deepcopy
import heapq

n,m = map(int,stdin.readline().rstrip().split())

li = [[0 for i in range(n+1)]for j in range(n+1)]

inf = 10**10

def all_pairs_shortest_paths(W):
    
    n = len(W)
    
    res = [[0] * n for i in range(n)]
    
    for i in range(n):
        for j in range(i, n):
            if i == j:
                val = 0
            elif W[i][j]:
                val = W[i][j]
            else:
                val = inf
            res[i][j] = res[j][i] = val
    
    for k in range(n):
        for u in range(n):
            for v in range(n):
                res[u][v] = min(res[u][v], res[u][k] + res[k][v])
    return res

lin = [list(map(int,stdin.readline().rstrip().split())) for _ in range(m)]

true = [True]*(n+1)
point = 0

for j in range(m):
    lis = []
    for num,i in enumerate(lin):
        if num != j:
            lis.append(i)
    liv = [[0 for e in range(n+1)]for o in range(n+1)]
    for kp in lis:
        liv[kp[0]][kp[1]] = 1
        liv[kp[1]][kp[0]] = 1
    kota = all_pairs_shortest_paths(liv)[1:]
    flag = True
    for kk in kota:
        if inf in kk[1:]:
            flag = False
    if flag:
        point += 1

print(m-point)

Solution (Python):
class UnionFind:
    def __init__(self, n):
        self.p = [-1]*n
        
        self.r = [1]*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 union(self, x, y):
        rx, ry = self.find(x), self.find(y)
 
        if rx != ry:
            if self.r[rx] > self.r[ry]:
                rx, ry = ry, rx
            if self.r[rx] == self.r[ry]:
                self.r[ry] += 1
            self.p[ry] += self.p[rx]
            self.p[rx] = ry
 
    def same(self, x, y):
        return self.find(x) == self.find(y)
 
    def count_member(self, x):
        return -self.p[self.find(x)]

n,m=map(int,input().split())
e=[]
for i in range(m):
  a,b=map(int,input().split())
  e.append((a-1,b-1))
ans=0
for i in range(m):
  uf=UnionFind(n)
  ok=False
  for j in range(m):
    if i!=j:
      a,b=e[j]
      uf.union(a,b)
  for k in range(n):
    t=uf.count_member(k)
    if t!=n:
      ok=True
      break
  if ok:ans+=1
print(ans)

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

N, M = map(int, input().split())
G = [[] for _ in [0]*N]
E = []
for _ in [0]*M:
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    G[a].append(b)
    G[b].append(a)
    E.append((a, b))


def dfs(v, s, g):
    if v == g:
        return True

    visited[v] = True

    for u in G[v]:
        if visited[u] or v == s and u == g:
            continue
        if dfs(u, s, g):
            return True

    return False


visited = [False]*N

cnt = 0
for a, b in E:
    visited = [False]*N
    visited[a] = True
    if not dfs(a, a, b):
        cnt += 1

print(cnt)

Solution (Python):
def search_leaf(edge:list):
    """ 葉を取得 """
    for v in range(N):
        if len(edge[v]) == 1: return v
    return -1

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

ans = 0
for _ in range(M):
    V = search_leaf(edge)
    if V == -1: break

    main_land = edge[V][0]
    edge[main_land].remove(V)
    edge[V] = []

    ans += 1

print(ans)