#include <bits/stdc++.h>

#define debug(x) cout <<"DEBUG"<<" "<< #x << ":" << x << '\n'
#define rep(i,n) for(int_fast32_t i = 0; i < ((int_fast32_t)(n)); i++)   // 0-indexed up
#define rep1(i,n) for(int_fast32_t i = 1; i <= ((int_fast32_t)(n)); i++) // 1-indexed up
#define rrep(i,n) for(int_fast32_t i = ((int_fast32_t)(n)-1); i >= 0; i--)  // 0-indexed down
#define rrep1(i,n) for(int_fast32_t i = ((int_fast32_t)(n)); i >= 1; i--)   // 1-indexed down
#define all(x) (x).begin(),(x).end()

using namespace std;

template<typename T>
using vec = vector<T>;
using i32 = int_fast32_t;
using i64 = int_fast64_t;
using u32 = uint_fast32_t;
using u64 = uint_fast64_t;
using ll = long long;
using ld = long double;
using vi = vec<int_fast32_t>;
using vl = vec<int_fast64_t>;
using vld = vec<ld>;
using vii = vec<vi>;
using PII = pair<int_fast32_t, int_fast32_t>;

template<class T>
using maxheap = std::priority_queue<T>;
template<class T>
using minheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<class T,class U> inline bool chmax(T &a, const U &b){if(a<b){a=b;return 1;}return 0;}
template<class T,class U> inline bool chmin(T &a, const U &b){if(a>b){a=b;return 1;}return 0;}

const ld Pi = std::acos(-1.0L);
constexpr ll infll = (1LL<<62)-1;
constexpr int inf = (1<<30)-1;
const int mod = 1000000007;
// const int mod = 998244353;


/*FUNCs=================================================*/
/* LowLink */
class lowLink {
public:
    using i32 = int_fast32_t;
    std::vector<i32> ord, low, articulation_points;
    std::vector<std::pair<i32, i32>> bridges;
    const std::vector<std::vector<i32>> &G;
private:
    std::vector<bool> seen;
    bool sorted = false;

    i32 inner_dfs(i32 u = 0, i32 p = -1, i32 k = 0) {
        seen[u] = true;
        low[u] = ord[u] = k;
        bool is_ar_pnt = false;
        for(const auto &v : G[u]) {
            if(!seen[v]) {
                k = inner_dfs(v, u, k+1);
                low[u] = std::min(low[u], low[v]);
                if(k != 1 && ord[u] <= low[v]) is_ar_pnt = true;
                if(ord[u] < low[v]) bridges.emplace_back(std::min(u, v), std::max(u, v));
            }
            else if(v != p) low[u] = std::min(low[u], ord[v]);
        }
        if(k == 1 && G[ord[0]].size() > 1) is_ar_pnt = true;
        if(is_ar_pnt) articulation_points.push_back(u);
        return k;
    }
public:
    explicit lowLink(const std::vector<std::vector<i32>> &graph, bool sort_Bridges_and_ArticulationPoints = false):
            ord(graph.size()), low(graph.size()), seen(graph.size()), sorted(sort_Bridges_and_ArticulationPoints), G(graph)
    {
        inner_dfs();
        if(sorted) {
            std::sort(bridges.begin(), bridges.end());
            std::sort(articulation_points.begin(), articulation_points.end());
        }
    }

    bool is_bridge(const i32 &a, const i32 &b) {
        if(!sorted) {
            std::cout << "error: member 'bridges' is not sorted";
            return false;
        }
        std::pair<i32, i32> p = std::make_pair(std::min(a, b), std::max(a, b));
        return p == *std::lower_bound(bridges.begin(), bridges.end(), p);
    }
    bool is_articulation_point(const i32 &a) {
        if(!sorted) {
            std::cout << "error: member 'articulation_points' is not sorted";
            return false;
        }
        return a == *std::lower_bound(articulation_points.begin(), articulation_points.end(), a);
    }
};


/*MAIN==================================================*/
signed main(){
    double START_TIME = clock();
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
//    cout << fixed << setprecision(15);

    i32 n,m, a,b, cnt = 0; cin >> n >> m;
    vii graph(n);
    rep(i,m) {
        cin >> a >> b;
        graph[--a].push_back(--b);
        graph[b].push_back(a);
    }

    lowLink l(graph);

    cout << l.bridges.size() << '\n';

//     printf("ElapsedTime: %5.3f ms\n",1000*((clock()-START_TIME)/CLOCKS_PER_SEC));
}


Measured memory_bytes: 3648