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 find(x):
    if par[x] < 0:
        return x
    else:
        tank = []
        while par[x] >= 0:
            tank.append(x)
            x = par[x]
        for elt in tank:
            par[elt] = x
        return 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())
edge=[]
for _ in range(m):
    a,b=map(int,input().split())
    a,b=a-1,b-1

    edge.append([a,b])


ans=0
for j in range(m):
    
    
    par = [-1]*n
    cnt=0
    for p in range(m):
        if p==j:
            continue
    
        e=edge[p]
        unite(e[0],e[1])  
          
    for k in range(n):
        if par[k]<0:
            cnt+=1

    if cnt>=2:
        ans+=1
    
    

    


print(ans)

Solution (Python):
from _collections import deque
n,m=map(int,input().split())
ab=[[0,0] for i in range(m)]
for i in range(m):
    ab[i][0],ab[i][1]=map(int,input().split())
ans=0
for i in range(m):
    edg=[[] for j in range(n+1)]
    dep=[-1]*(n+1)
    dep[0]=1
    dep[1]=1
    for j in range(m):
        if j!=i:
            a,b=ab[j][0],ab[j][1]
            edg[a].append(b)
            edg[b].append(a)
    data=deque([1])
    while len(data)>0:
        p=data.popleft()
        for j in edg[p]:
            if dep[j]==-1:
                dep[j]=1
                data.append(j)
    if not all(dep[i]==1 for i in range(n+1)):ans+=1
print(ans)

Solution (Python):
import sys
sys.setrecursionlimit(10**9)
class UnionFind:
  def __init__(self, n):
    self.n = [-1]*n
    self.r = [0]*n
    self.siz = n

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

  def unite(self, x, y):
    x = self.find_root(x)
    y = self.find_root(y)
    if x == y:
      return
    elif self.r[x] > self.r[y]:
      self.n[x] += self.n[y]
      self.n[y] = x
    else:
      self.n[y] += self.n[x]
      self.n[x] = y
      if self.r[x] == self.r[y]:
        self.r[y] += 1
    self.siz -= 1

  def root_same(self, x, y):
    return self.find_root(x) == self.find_root(y)

  def count(self, x):
    return -self.n[self.find_root(x)]

  def size(self):
    return self.siz

n,m=map(int,input().split())
edges=[list(map(int,input().split()))for _ in range(m)]
ans=0
for i in range(m):
  u=UnionFind(n)
  for j in range(m):
    if j==i:continue
    a,b=edges[j]
    a-=1
    b-=1
    u.unite(a,b)
  if u.size()!=1:ans+=1
print(ans)

Solution (Python):
class DisjointSet:
    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 same(self, x, y):
        return self.find(x) == self.find(y)

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


N, M, *ab = map(int, open(0).read().split())
edges = [(a - 1, b - 1) for a, b in zip(*[iter(ab)] * 2)]

ans = 0
for i in range(M):
    ds = DisjointSet(N)
    for j in range(M):
        if i == j:
            continue
        ds.union(*edges[j])
    if len([-p for p in ds.parents if p < 0]) > 1:
        ans += 1
print(ans)

Solution (Python):
from sys import stdin
nii=lambda:map(int,stdin.readline().split())
lnii=lambda:list(map(int,stdin.readline().split()))
from collections import deque
from copy import deepcopy

n,m=nii()
l=[lnii() for i in range(m)]

def BFS(t_l):
  tree=[[] for i in range(n)]
  for a,b in t_l:
    a-=1
    b-=1
    tree[a].append(b)
    tree[b].append(a)

  dist=[-1 for i in range(n)]
  dist[0]=0

  que=deque()
  que.append(0)

  while que:
    x=que.popleft()
    for i in tree[x]:
      if dist[i]==-1:
        que.append(i)
        dist[i]=dist[x]+1

  return dist

ans=0
for i in range(m):
  t_l=deepcopy(l)
  del t_l[i]
  dist=BFS(t_l)
  if -1 in dist:
    ans+=1

print(ans)

Solution (Python):
import sys

sys.setrecursionlimit(10**7)
def I(): return int(sys.stdin.readline().rstrip())
def MI(): return map(int,sys.stdin.readline().rstrip().split())
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))  
def LI2(): return list(map(int,sys.stdin.readline().rstrip()))  
def S(): return sys.stdin.readline().rstrip()
def LS(): return list(sys.stdin.readline().rstrip().split())  
def LS2(): return list(sys.stdin.readline().rstrip())  


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


N,M = MI()
edges = [tuple(MI()) for _ in range(M)]

ans = 0
for i in range(M):
    U = UnionFind(N)
    for j in range(M):
        if j != i:
            a,b = edges[j]
            U.unite(a,b)
    x,y = edges[i]
    if not U.same_check(x,y):
        ans += 1

print(ans)

Solution (Python):
import sys
input = sys.stdin.buffer.readline
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
    E.append((a, b))


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


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

Solution (Python):
class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]
    def find(self, x):
        """
        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 と y のグループを結合
        """
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]
    def is_same(self, x, y):
        """
        x と y が同じグループか否か
        """
        return self.find(x) == self.find(y)
    def get_size(self, x):
        """
        x が属するグループの要素数
        """
        x = self.find(x)
        return self.size[x]


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

ans = 0

for ng in range(M):
  uf = UnionFind(N)
  for i in range(M):
    if i == ng:
      continue
    else:
      uf.union(E[i][0],E[i][1])
  if uf.get_size(0) != N:
    ans += 1

print(ans)

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

class UnionFind:
    def __init__(self,N):
        self.parent = [i for i in range(N)]
        self._size = [1] * N
        self.count = 0
    def root(self,a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.root(self.parent[a])
            return self.parent[a]
    def is_same(self,a,b):
        return self.root(a) == self.root(b)
    def unite(self,a,b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb: return
        if self._size[ra] < self._size[rb]: ra,rb = rb,ra
        self._size[ra] += self._size[rb]
        self.parent[rb] = ra
        self.count += 1
    def size(self,a):
        return self._size[self.root(a)]

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

Solution (Python):
class UnionFind:
    def __init__(self, N):
        self.N = N

        
        
        self.parent = [-1] * N

    def root(self, i):
        if self.parent[i] < 0:
            return i

        r = self.root(self.parent[i])
        self.parent[i] = r
        return r

    def unite(self, i, j):
        i = self.root(i)
        j = self.root(j)

        if i == j:
            return

        if i > j:
            i, j = j, i

        self.parent[i] += self.parent[j]
        self.parent[j] = i
        

    def same(self, i, j):
        return self.root(i) == self.root(j)

    def size(self, i):
        return -self.parent[self.root(i)]

    def roots(self):
        return [self.root(i) for i in range(self.N)]

    def groupcount(self):
        return len(set(self.roots()))

N, M = map(int, input().split())
edges = [[int(x) - 1 for x in input().split()] for _ in range(M)]

ans = 0


for i in range(M):
    
    forest = UnionFind(N)

    
    for i, j in edges[:i] + edges[i+1:]:
        forest.unite(i, j)

    
    
    if forest.groupcount() != 1:
        ans += 1

print(ans)

Solution (Python):
from collections import deque


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

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


def main():
    ans = 0

    for b in bridge:
        seen = [0] * N
        seen[0] = 1
        
        
        que = deque([0])
        while que:
            v = que.popleft()
            for nv in to[v]:
                if set([v, nv]) == b:
                    continue
                if not seen[nv]:
                    seen[nv] = 1
                    que.append(nv)

        if seen != [1] * N:
            ans += 1
    print(ans)


if __name__ == "__main__":
    main()

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

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

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

        if x == y:
            return

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

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

    def 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())
    G = []
    for _ in range(M):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        G.append((a,b))
    ans = 0
    for i in range(M):
        uni = UnionFind(N)
        for j in range(M):
            if i == j:
                continue
            uni.union(G[j][0],G[j][1])
        if uni.group_count() >= 2:
            ans += 1

    print(ans)
if __name__ == "__main__":
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10**9)
n,m=map(int,input().split())
ab=[[0,0]  for i in range(m)]
for i in range(m):
    ab[i][0],ab[i][1]=map(int,input().split())
ans=0
for i in range(m):
    root=[j for j in range(n+1)]
    root[0]=1
    def r(x):
        if root[x]==x:
            return x
        else:
            root[x]=r(root[x])
            return root[x]
    def unite(x,y):
        x=r(x)
        y=r(y)
        if x==y:
            return
        else:
            x,y=min(x,y),max(x,y)

            root[y]=x
    for j in range(m):
        if j!=i:
            a,b=ab[j][0],ab[j][1]
            unite(a,b)

    if not all(r(j)==1 for j in range(1,n+1)):
        ans+=1
print(ans)

Solution (Python):
from _collections import deque
import sys
sys.setrecursionlimit(10**9)
n,m=map(int,input().split())
ab=[[0,0]  for i in range(m)]
for i in range(m):
    ab[i][0],ab[i][1]=map(int,input().split())
ans=0
for i in range(m):
    edg=[[] for j in range(n+1)]
    for j in range(m):
        if j!=i:
            a,b=ab[j][0],ab[j][1]
            edg[a].append(b)
            edg[b].append(a)
    che=[0]*(n+1)
    che[0]=1
    def search(x):
        che[x]=1
        for j in edg[x]:
            if che[j]==0:
                search(j)
    search(1)
    if not all(che[j]==1 for j in range(n+1)):
        ans+=1
print(ans)

Solution (Python):
from _collections import deque
n,m=map(int,input().split())
ab=[[0,0]  for i in range(m)]
for i in range(m):
    ab[i][0],ab[i][1]=map(int,input().split())
ans=0
for i in range(m):
    edg=[[] for j in range(n+1)]
    for j in range(m):
        if j!=i:
            a,b=ab[j][0],ab[j][1]
            edg[a].append(b)
            edg[b].append(a)
    che=[0]*(n+1)
    che[0]=1
    data=deque([1])
    while len(data)>0:
        p=data.popleft()
        che[p]=1
        for j in range(len(edg[p])):
            r=edg[p][j]
            if che[r]==0:
                data.append(r)
                che[r]=1
    if not all(che[j]==1 for j in range(n+1)):
        ans+=1
print(ans)

Solution (Python):
from itertools import combinations

class unionfind:
    def __init__(self,n):
        self.par=[i for i in range(n)]
        self.rank=[1]*n

    def root(self,a):
        if self.par[a]==a : return a
        parent=self.root(self.par[a])
        self.par[a]=parent
        return parent

    def unite(self,a,b):
        ra,rb=self.root(a),self.root(b)
        if ra==rb : return
        if self.rank[ra]>self.rank[rb]:
            ra,rb=rb,ra
        self.par[rb]=ra
        self.rank[ra]+=1

    def same(self,a,b):
        return self.root(a)==self.root(b)


def main():
    n,m=map(int,input().split())
    edges=[tuple(map(int,input().split())) for _ in range(m)]

    sm=0
    for e_remove in edges:
        uf=unionfind(n)
        for e in edges:
            if e==e_remove : continue
            uf.unite(e[0]-1,e[1]-1)

        for a in combinations(range(n),2):
            if not uf.same(a[0],a[1]):
                break
        else : continue
        sm+=1

    print(sm)

main()

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

for i in range(M):
  a, b = map(int, input().split())
  a, b = a-1, b-1
  graph[a].append(b)
  graph[b].append(a) 
    
def dfs(x,g):
    if vis[x]:return
    vis[x]=1
    for i in g[x]:
     dfs(i,g)
    return

ans=0
for i in range(len(graph)):
    for j in range(len(graph[i])):
        t=graph[i]
        gn=graph[0:i]+[t[0:j]+t[j+1:]]+graph[i+1:]
        vis=[0]*N
        dfs(0,gn)
        if not(all(vis)):
            
            ans+=1
print(ans)

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

N, M = map(int, input().split())
ab = []
for i in range(M):
    ab.append(list(map(int,input().split())))

out=0
for k in range(M):
    Network = UnionFind(N)
    for i in range(M):
        if i!=k:
            a,b = ab[i][0], ab[i][1]
            Network.union(a-1,b-1)
    if Network.group_count() != 1:
        out+=1

print(out)

Solution (Python):


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

def lowlink(g, root=0):
    n = len(g)
    order = [n]*n
    low = [n]*n

    s = [root]
    cnt = 0
    par = [-1]*n
    seq = []
    while s:
        v = s.pop()
        if order[v] != n:
            continue
        order[v] = cnt
        seq.append(v)
        low[v] = cnt
        cnt += 1
        for u in g[v]:
            if order[u] < cnt:
                if par[v] != u:
                    low[v] = min(low[v], order[u])
                    continue
            else:
                par[u] = v
                s.append(u)
    child = [[] for _ in range(n)]
    for v in range(n):
        if par[v] != -1:
            child[par[v]].append(v)
    seq.reverse()
    for v in seq:
        for u in child[v]:
            low[v] = min(low[v], low[u])
    
    bridge = []
    for p in range(n):
        for c in child[p]:
            if order[p] < low[c]:
                bridge.append((p, c))

    
    AP = []
    for v in range(n):
        if v == root:
            if len(child[v]) >= 2:
                AP.append(v)
        else:
            for c in child[v]:
                if order[v] <= low[c]:
                    AP.append(v)
                    break
    return AP, bridge

_, bridge = lowlink(g, 0)
print(len(bridge))

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

def lowlink(g, root=0):
    n = len(g)
    order = [n]*n
    low = [n]*n

    s = [root]
    cnt = 1
    par = [-1]*n
    seq = []
    while s:
        v = s.pop()
        if order[v] != n:
            continue
        order[v] = cnt
        seq.append(v)
        low[v] = cnt
        cnt += 1
        for u in g[v]:
            if order[u] < cnt:
                if par[v] != u:
                    low[v] = min(low[v], order[u])
                    continue
            else:
                par[u] = v
                s.append(u)
    child = [[] for _ in range(n)]
    for v in range(n):
        if par[v] != -1:
            child[par[v]].append(v)
    seq.reverse()
    for v in seq:
        for u in child[v]:
            low[v] = min(low[v], low[u])
    
    bridge = []
    for p in range(n):
        for c in child[p]:
            if order[p] < low[c]:
                bridge.append((p, c))

    
    AP = []
    for v in range(n):
        if v == root:
            if len(child[v]) >= 2:
                AP.append(v)
        else:
            for c in child[v]:
                if order[v] <= low[c]:
                    AP.append(v)
                    break
    return AP, bridge

_, bridge = lowlink(g, 0)
print(len(bridge))

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

def lowlink(g, root=0):
    n = len(g)
    order = [n]*n
    low = [n]*n

    s = [root]
    cnt = 1
    par = [-1]*n
    seq = []
    while s:
        v = s.pop()
        if order[v] != n:
            continue
        order[v] = cnt
        seq.append(v)
        low[v] = cnt
        cnt += 1
        for u in g[v]:
            if order[u] < cnt:
                if par[v] != u:
                    low[v] = min(low[v], order[u])
                    continue
            else:
                par[u] = v
                s.append(u)
    child = [[] for _ in range(n)]
    for v in range(n):
        if par[v] != -1:
            child[par[v]].append(v)
    seq.reverse()
    for v in seq:
        for u in child[v]:
            low[v] = min(low[v], low[u])
    
    bridge = []
    for p in range(n):
        for c in child[p]:
            if order[p] < low[c]:
                bridge.append((p, c))

    
    AP = []
    for v in range(n):
        if v == root:
            if len(child[v]) >= 2:
                AP.append(v)
        else:
            for c in child[v]:
                if order[v] <= low[c]:
                    AP.append(v)
                    break
    return AP, bridge

_, bridge = lowlink(g, 0)
print(len(bridge))

Solution (Python):
import itertools

N,M = list(map(int, input().split()))
ABs = [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 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
    size[y] = size[x] + size[y]
    size[x] = 0


loop_list = list(itertools.combinations(ABs, M-1))


ans = 0
for loop in loop_list:
    
    par = [i for i in range(N+1)]
    size = [1 for _ in range(N+1)]

    for bridge in loop:
        unite(bridge[0], bridge[1])
    


    if(max(size) != N):
        ans += 1

print(ans)

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

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

ans = 0
for i in range(m):
    UF = UnionFind(n)
    for j in range(m):
        if i == j:
            continue
        UF.union(ab[j][0] - 1, ab[j][1] - 1)
    if UF.size(0) != n:
        ans += 1
print(ans)

Solution (Python):
import copy
N,M=map(int,input().split())
path_matrix=[[0 for i in range(N)] for j in range(N)]
L=[[] for i in range(M)]

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

color_white=["W" for i in range(N)]
color_black=["B" for i in range(N)]
visited=copy.deepcopy(color_white)

def path(x,y):
    path_matrix[x-1][y-1]=0
    path_matrix[y-1][x-1]=0
    return DFS(x,path_matrix)

def DFS(x,tim):
    visited[x-1]="B"
    if visited==color_black:
        return True
    total_ans=0
    for i in range(N):
        if tim[x-1][i]==1 and visited[i]=="W":
            total_ans=int(DFS(i+1,tim))

    return total_ans
    
ans=0
for i in range(M):
    visited=copy.deepcopy(color_white)
    if path(L[i][0],L[i][1])==0:
        ans+=1
    path_matrix[L[i][0]-1][L[i][1]-1]=1
    path_matrix[L[i][1]-1][L[i][0]-1]=1

print(ans)

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

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

def dfs(now):
    searched[now] = True
    for next in graph[now]:
        if searched[next]:
            continue
        if min(now, next) == a and max(now, next) == b:
            continue
        dfs(next)

ans = M
for i in range(M):
    a, b = edge[i]
    searched = [False] * N
    dfs(0)
    if sum(searched) == N:
        ans -= 1

print(ans)

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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


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

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

out = 0
for broken in range(M):
    Network = UnionFind(N)
    for j in range(M):
        if j!=broken:
            A,B=AB[j][0],AB[j][1]
            Network.union(A-1, B-1)
    if Network.group_count()==2:
        out+=1
print(out)

Solution (Python):
class UnionFind():
    def __init__(self,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
        

N,M = map(int, input().split())
AB = []
for _ in range(M):
    AB.append(list(map(int, input().split())))
ans = 0
for i in range(M):
    if i == M-1:
        ab = AB[:M-1]
    else:
        ab = AB[:i]+AB[i+1:]
    uf = UnionFind(N)
    for j in ab:
        uf.union(j[0]-1,j[1]-1)
    if uf.parents[uf.find(0)] != - N:
        ans += 1
print(ans)

Solution (Python):
class UnionFind():
    def __init__(self, n):
        self.parents = list(range(n))
        self.size = [1] * n
    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 x == y:
            return
        if self.size[x] < self.size[y]:
            self.size[y] += self.size[x]
            self.parents[x] = y
        else:
            self.size[x] += self.size[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())
num=[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:
            uf.union(num[j][0]-1,num[j][1]-1)
    if uf.size[uf.find(0)]!=n:
        ans+=1
print(ans)

Solution (Python):
from sys import stdin
def input():
    return stdin.readline().strip()

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



ans = 0
for i in range(m):
    seen = [True] * n
    todo = []
    start = a[i]
    goal = b[i]
    seen[start] = False
    for j in edge[start]:
        if j == goal:
            continue
        else:
            todo.append(j)
            seen[j] = False

    while len(todo) > 0 and seen[goal]:
        j = todo.pop(-1)
        for k in edge[j]:
            if seen[k]:
                todo.append(k)
                seen[k] = False

    if seen[goal]:
        ans += 1

print(ans)