class Unionfind:

    def __init__(self, n):

        self.par = [-1]*n

        self.rank = [1]*n

    

    def root(self, x):

        p = x

        

        while not self.par[p]<0:

            p = self.par[p]

        

        while x!=p:

            tmp = x

            x = self.par[x]

            self.par[tmp] = p

        

        return p

    

    def unite(self, x, y):

        rx, ry = self.root(x), self.root(y)

        

        if rx==ry: return False

        

        if self.rank[rx]<self.rank[ry]:

            rx, ry = ry, rx

        

        self.par[rx] += self.par[ry]

        self.par[ry] = rx

    

        if self.rank[rx]==self.rank[ry]:

            self.rank[rx] += 1

    

    def is_same(self, x, y):

        return self.root(x)==self.root(y)

    

    def count(self, x):

        return -self.par[self.root(x)]



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

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

ans = 0



for i in range(M):

    uf = Unionfind(N)

    

    for j in range(M):

        if j==i:

            continue

        

        a, b = ab[j][0], ab[j][1]

        uf.unite(a-1, b-1)

    

    if uf.count(0)!=N:

        ans += 1



print(ans)
from collections import *



def bfs():

    q = deque([0])

    visited = [False]*N

    visited[0] = True

    

    while q:

        v = q.popleft()

        

        for nv in range(N):

            if G[v][nv]==1:

                if not visited[nv]:

                    visited[nv] = True

                    q.append(nv)

    

    return False in visited

    

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

G = [[0]*N for _ in range(N)]

edges = []



for _ in range(M):

    a, b = list(map(int, input().split()))

    G[a-1][b-1] = 1

    G[b-1][a-1] = 1

    edges.append((a-1, b-1))



ans = 0



for a, b in edges:

    G[a][b] = 0

    G[b][a] = 0

    

    if bfs():

        ans += 1

    

    G[a][b] = 1

    G[b][a] = 1



print(ans)
class Unionfind:
    def __init__(self, n):
        self.par = [-1] * n
        self.rank = [1] * n

    def root(self, x):
        p = x
        while not self.par[p] < 0:
            p = self.par[p]
        while x != p:
            tmp = x
            x = self.par[x]
            self.par[tmp] = p
        return p

    def unite(self, x, y):
        rx, ry = self.root(x), self.root(y)
        if rx == ry:
            return False
        if self.rank[rx] < self.rank[ry]:
            rx, ry = ry, rx
        self.par[rx] += self.par[ry]
        self.par[ry] = rx
        if self.rank[rx] == self.rank[ry]:
            self.rank[rx] += 1

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

    def count(self, x):
        return -self.par[self.root(x)]


N, M = list(map(int, input().split()))
ab = [tuple(map(int, input().split())) for _ in range(M)]
ans = 0
for i in range(M):
    uf = Unionfind(N)
    for j in range(M):
        if j == i:
            continue
        a, b = ab[j][0], ab[j][1]
        uf.unite(a - 1, b - 1)
    if uf.count(0) != N:
        ans += 1
print(ans)

from collections import *


def bfs():
    q = deque([0])
    visited = [False] * N
    visited[0] = True
    while q:
        v = q.popleft()
        for nv in range(N):
            if G[v][nv] == 1:
                if not visited[nv]:
                    visited[nv] = True
                    q.append(nv)
    return False in visited


N, M = list(map(int, input().split()))
G = [[0] * N for _ in range(N)]
edges = []
for _ in range(M):
    a, b = list(map(int, input().split()))
    G[a - 1][b - 1] = 1
    G[b - 1][a - 1] = 1
    edges.append((a - 1, b - 1))
ans = 0
for a, b in edges:
    G[a][b] = 0
    G[b][a] = 0
    if bfs():
        ans += 1
    G[a][b] = 1
    G[b][a] = 1
print(ans)

-class Unionfind: -    def __init__(self, n): -        self.par = [-1] * n -        self.rank = [1] * n +from collections import * -    def root(self, x): -        p = x -        while not self.par[p] < 0: -            p = self.par[p] -        while x != p: -            tmp = x -            x = self.par[x] -            self.par[tmp] = p -        return p -    def unite(self, x, y): -        rx, ry = self.root(x), self.root(y) -        if rx == ry: -            return False -        if self.rank[rx] < self.rank[ry]: -            rx, ry = ry, rx -        self.par[rx] += self.par[ry] -        self.par[ry] = rx -        if self.rank[rx] == self.rank[ry]: -            self.rank[rx] += 1 - -    def is_same(self, x, y): -        return self.root(x) == self.root(y) - -    def count(self, x): -        return -self.par[self.root(x)] +def bfs(): +    q = deque([0]) +    visited = [False] * N +    visited[0] = True +    while q: +        v = q.popleft() +        for nv in range(N): +            if G[v][nv] == 1: +                if not visited[nv]: +                    visited[nv] = True +                    q.append(nv) +    return False in visited -ab = [tuple(map(int, input().split())) for _ in range(M)] +G = [[0] * N for _ in range(N)] +edges = [] +for _ in range(M): +    a, b = list(map(int, input().split())) +    G[a - 1][b - 1] = 1 +    G[b - 1][a - 1] = 1 +    edges.append((a - 1, b - 1)) -for i in range(M): -    uf = Unionfind(N) -    for j in range(M): -        if j == i: -            continue -        a, b = ab[j][0], ab[j][1] -        uf.unite(a - 1, b - 1) -    if uf.count(0) != N: +for a, b in edges: +    G[a][b] = 0 +    G[b][a] = 0 +    if bfs(): +    G[a][b] = 1 +    G[b][a] = 1