from scipy.sparse.csgraph import floyd_warshall

import numpy as np

import sys



input = sys.stdin.readline



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

AB = []

edge = np.zeros((N, N), dtype=int)

for _ in range(M):

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

    a -= 1

    b -= 1

    AB.append((a, b))

    edge[a][b] = 1

    edge[b][a] = 1



ans = 0

for i in range(M):

    graph = np.copy(edge)

    a, b = AB[i]

    graph[a][b] = 0

    graph[b][a] = 0

    fw = floyd_warshall(graph)

    if fw.max() > 10000:

        ans += 1



print(ans)

import sys

input = sys.stdin.buffer.readline

sys.setrecursionlimit(10 ** 7)





class UF_tree:

    def __init__(self, n):

        self.root = [-1] * (n + 1)  # -1ならそのノードが根,で絶対値が木の要素数

        self.rank = [0] * (n + 1)



    def find(self, x):  # xの根となる要素番号を返す

        if self.root[x] < 0:

            return x

        else:

            self.root[x] = self.find(self.root[x])

            return self.root[x]



    def isSame(self, x, y):

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



    def unite(self, x, y):

        x = self.find(x)

        y = self.find(y)

        if x == y:

            return

        elif self.rank[x] < self.rank[y]:

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

            self.root[x] = y

        else:

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

            self.root[y] = x

            if self.rank[x] == self.rank[y]:

                self.rank[x] += 1



    def getNodeLen(self, x):

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





if __name__ == "__main__":

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

    AB = tuple(tuple(map(int, input().split())) for _ in range(M))



    ans = 0

    for i in range(M):

        uf = UF_tree(N)

        for j, (a, b) in enumerate(AB):

            if i == j:

                continue

            uf.unite(a, b)

        a, b = AB[i]

        if not uf.isSame(a, b):

            ans += 1

    print(ans)
from scipy.sparse.csgraph import floyd_warshall
import numpy as np
import sys

input = sys.stdin.readline
N, M = list(map(int, input().split()))
AB = []
edge = np.zeros((N, N), dtype=int)
for _ in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    AB.append((a, b))
    edge[a][b] = 1
    edge[b][a] = 1
ans = 0
for i in range(M):
    graph = np.copy(edge)
    a, b = AB[i]
    graph[a][b] = 0
    graph[b][a] = 0
    fw = floyd_warshall(graph)
    if fw.max() > 10000:
        ans += 1
print(ans)

import sys

input = sys.stdin.buffer.readline
sys.setrecursionlimit(10**7)


class UF_tree:
    def __init__(self, n):
        self.root = [-1] * (n + 1)  # -1ならそのノードが根,で絶対値が木の要素数
        self.rank = [0] * (n + 1)

    def find(self, x):  # xの根となる要素番号を返す
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]

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

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

    def getNodeLen(self, x):
        return -self.root[self.find(x)]


if __name__ == "__main__":
    N, M = list(map(int, input().split()))
    AB = tuple(tuple(map(int, input().split())) for _ in range(M))
    ans = 0
    for i in range(M):
        uf = UF_tree(N)
        for j, (a, b) in enumerate(AB):
            if i == j:
                continue
            uf.unite(a, b)
        a, b = AB[i]
        if not uf.isSame(a, b):
            ans += 1
    print(ans)

-from scipy.sparse.csgraph import floyd_warshall -import numpy as np -input = sys.stdin.readline -N, M = list(map(int, input().split())) -AB = [] -edge = np.zeros((N, N), dtype=int) -for _ in range(M): -    a, b = list(map(int, input().split())) -    a -= 1 -    b -= 1 -    AB.append((a, b)) -    edge[a][b] = 1 -    edge[b][a] = 1 -ans = 0 -for i in range(M): -    graph = np.copy(edge) -    a, b = AB[i] -    graph[a][b] = 0 -    graph[b][a] = 0 -    fw = floyd_warshall(graph) -    if fw.max() > 10000: -        ans += 1 -print(ans) +input = sys.stdin.buffer.readline +sys.setrecursionlimit(10**7) + + +class UF_tree: +    def __init__(self, n): +        self.root = [-1] * (n + 1)  # -1ならそのノードが根,で絶対値が木の要素数 +        self.rank = [0] * (n + 1) + +    def find(self, x):  # xの根となる要素番号を返す +        if self.root[x] < 0: +            return x +        else: +            self.root[x] = self.find(self.root[x]) +            return self.root[x] + +    def isSame(self, x, y): +        return self.find(x) == self.find(y) + +    def unite(self, x, y): +        x = self.find(x) +        y = self.find(y) +        if x == y: +            return +        elif self.rank[x] < self.rank[y]: +            self.root[y] += self.root[x] +            self.root[x] = y +        else: +            self.root[x] += self.root[y] +            self.root[y] = x +            if self.rank[x] == self.rank[y]: +                self.rank[x] += 1 + +    def getNodeLen(self, x): +        return -self.root[self.find(x)] + + +if __name__ == "__main__": +    N, M = list(map(int, input().split())) +    AB = tuple(tuple(map(int, input().split())) for _ in range(M)) +    ans = 0 +    for i in range(M): +        uf = UF_tree(N) +        for j, (a, b) in enumerate(AB): +            if i == j: +                continue +            uf.unite(a, b) +        a, b = AB[i] +        if not uf.isSame(a, b): +            ans += 1 +    print(ans)