#include<bits/stdc++.h>

using namespace std;

struct Edge {
	int src, dst;
	Edge(int f, int t) {
		src = f;
		dst = t;
	}
};

using Edges = vector<Edge>;
using Graph = vector<Edges>;

//２重辺連結成分と橋のリストを求める
pair<vector<int>, Edges> bridge(const Graph& g) {
	const int n = g.size();
	int idx = 0, s = 0, t = 0, k = 0;
	vector<int>ord(n, -1), onS(n), stk(n), roots(n), cmp(n);
	Edges brdg;
	function<void(int, int)> dfs = [&](int v, int u) {
		ord[v] = idx++;
		stk[s++] = v;
		onS[v] = true;
		roots[t++] = v;
		for (auto& e : g[v]) {
			int w = e.dst;
			if (ord[w] == -1)dfs(w, v);
			else if (u != w && onS[w])
				while (ord[roots[t - 1]]>ord[w])--t;
		}
		if (v == roots[t - 1]) {
			brdg.emplace_back(u, v);
			while (true) {
				int w = stk[--s];
				onS[w] = false;
				cmp[w] = k;
				if (v == w)break;
			}
			--t;
			++k;
		}
	};
	for (int u = 0; u<n; ++u) {
		if (ord[u] == -1) {
			dfs(u, n);
			brdg.pop_back();
		}
	}
	return make_pair(cmp, brdg);
}

int main() {
    int V, E;
    cin >> V >> E;
    Graph g(V);
    for (int i = 0; i<E; ++i) {
        int s, t; cin >> s >> t;
        --s;
        --t;
        g[s].emplace_back(s, t);
        g[t].emplace_back(t, s);
    }
    Edges es = bridge(g).second;
    cout<<es.size()<<endl;
}