#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n - 1); i >= 0; i--)
#define all(x) (x).begin(), (x).end()
#define sz(x) int(x.size())
#define get_unique(x) x.erase(unique(all(x)), x.end());
typedef long long ll;
typedef complex<double> Complex;
const int INF = 1e9;
const ll MOD = 1e9 + 7;
const ll LINF = 1e18;
template <class T>
bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
bool chmin(T& a, const T& b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
vector<T> make_vec(size_t a) {
    return vector<T>(a);
}
template <class T, class... Ts>
auto make_vec(size_t a, Ts... ts) {
    return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...));
}
struct LowLink {
    int n;
    vector<int> ord, low, data, ArticulationPoints;
    vector<pair<int, int>> Bridge;
    LowLink(vector<vector<int>>& g, int s = 0)
        : n(sz(g)), ord(n, -1), low(n), data(n, -1) {
        int k = 0;
        dfs(s, -1, k, g);
        sort(all(ArticulationPoints));
        sort(all(Bridge));
    }
    int root(int x) {
        return (data[x] < 0) ? x : data[x] = root(data[x]);
    }
    bool unite(int x, int y) {
        x = root(x);
        y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        return x != y;
    }
    void dfs(int now, int pre, int& k, vector<vector<int>>& g) {
        ord[now] = k;
        k++;
        low[now] = ord[now];
        bool ok = 0;
        int cnt = 0;
        for (int nxt : g[now]) {
            if (nxt == pre) continue;
            if (ord[nxt] == -1) {
                dfs(nxt, now, k, g);
                chmin(low[now], low[nxt]);
                cnt++;
                if (low[nxt] >= ord[now]) {
                    ok = 1;
                }
                if (ord[now] < low[nxt]) {
                    Bridge.emplace_back(min(now, nxt), max(now, nxt));
                } else {
                    unite(now, nxt);
                }
            } else {
                chmin(low[now], ord[nxt]);
            }
        }
        if (pre == -1) {
            if (cnt > 1) ArticulationPoints.push_back(now);
        } else {
            if (ok) ArticulationPoints.push_back(now);
        }
    }
};
struct TwoEdgeConnectedComponents : LowLink {
    int n;
    vector<int> comp;
    TwoEdgeConnectedComponents(vector<vector<int>>& g, vector<vector<int>>& t,
                               int s = 0)
        : n(sz(g)), comp(n, -1), LowLink(g, s) {
        int k = 0;
        rep(i, n) {
            if (comp[root(i)] == -1) {
                comp[root(i)] = k;
                k++;
            }
        }
        t.resize(k);
        for (auto p : Bridge) {
            int u, v;
            tie(u, v) = p;
            t[comp[root(u)]].push_back(comp[root(v)]);
            t[comp[root(v)]].push_back(comp[root(u)]);
        }
    }
    int operator[](int& x) {
        return comp[root(x)];
    }
};
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> g(n);
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        a--;
        b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    LowLink ll(g);
    cout << ll.Bridge.size() << endl;
}

Measured memory_bytes: 256