#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <limits>
#include <cstdlib>
#include <regex>
#include <list>
#include <stack>
using namespace std;

double inf = numeric_limits<double>::infinity();

#define REP(i,n) for(int i=0;i<n;i++)
using LL = long long int;
LL GCD(LL a,LL b){ if(a<b) return GCD(b,a); else if(a%b==0) return b; else return GCD(b,a%b); }
LL LCM(LL a,LL b){ return (a/GCD(a,b))*b; }

vector<vector<LL>> v;
vector<LL> color;

bool visited[ 100000 ];

class Graph
{
    int V;    // No. of vertices
    bool directed;
    std::list<int> *adj;    // An array of adjacency lists
    
    // A recursive function to print DFS starting from v
    void DFSUtil(int v, bool visited[]);
public:
    // Constructor and Destructor
    Graph(int V, bool directed)
    {
        this->V = V;
        this->directed = directed;
        adj = new std::list<int>[V];
    }
    ~Graph() { delete [] adj; }
    
    // Method to add an edge
    void addEdge(int v, int w);
    
    // The main function that returns true if the graph is strongly
    // connected, otherwise false
    bool isSC();
    
    // Function that returns reverse (or transpose) of this graph
    Graph* getTranspose();
};

// A recursive function to print DFS starting from v
void Graph::DFSUtil(int v, bool visited[])
{
    // Mark the current node as visited and print it
    visited[v] = true;
    
    // Recur for all the vertices adjacent to this vertex
    
    std::list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            DFSUtil(*i, visited);
}

// Function that returns reverse (or transpose) of this graph
Graph* Graph::getTranspose()
{
    Graph* g = new Graph(V, directed);
    for (int v = 0; v < V; v++)
    {
        // Recur for all the vertices adjacent to this vertex
        std::list<int>::iterator i;
        for(i = adj[v].begin(); i != adj[v].end(); ++i)
        {
            g->adj[*i].push_back(v);
        }
    }
    return g;
}

void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w);
    
    if ( !directed) adj[w].push_back(v);
}

// The main function that returns true if graph is strongly connected
bool Graph::isSC()
{
    // Step 1: Mark all the vertices as not visited (For first DFS)
    
    for (int i = 0; i < V; i++)
        visited[i] = false;
    
    // Step 2: Do DFS traversal starting from first vertex.
    DFSUtil(0, visited);
    
    // If DFS traversal doesn’t visit all vertices, then return false.
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
            return false;
    
    // Step 3: Create a reversed graph
    Graph* gr = getTranspose();
    
    // Step 4: Mark all the vertices as not visited (For second DFS)
    for(int i = 0; i < V; i++)
        visited[i] = false;
    
    // Step 5: Do DFS for reversed graph starting from first vertex.
    // Starting Vertex must be same starting point of first DFS
    gr->DFSUtil(0, visited);
    
    // If all vertices are not visited in second DFS, then
    // return false
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
            return false;
    
    return true;
}

int main() {
    int n, m;
    cin >> n >> m;
    int a[m];
    int b[m];
    REP(i,m) {
        int k,l;
        cin >> k >> l;
        a[i] = k - 1;
        b[i] = l - 1;
    }
    
    int cnt = 0;
    REP(i,m) {
        Graph g(n, false);
        REP(j,m) {
            if (i != j) {
                g.addEdge(a[j], b[j]);
            }
        }
        if (!g.isSC()) {
            cnt++;
        }
    }
    cout << cnt << endl;
    
    
    
}


Measured memory_bytes: 512