class UF{
  int[] par;
  this(int n){
    par.length=n;
    foreach(i; 0..n) par[i]=i;
  }
  int find(int x){
    if(x==par[x]) return par[x];
    else return par[x]=find(par[x]);
  }
  void unite(int x, int y){
    if((x=find(x))!=(y=find(y))) par[x]=y;
  }
  bool same(int x, int y){
    return find(x)==find(y);
  }
}

void main(){
  import std.stdio, std.string, std.conv, std.algorithm;
  import std.typecons;

  int n, m; rd(n, m);
  alias Edge=Tuple!(int, int);
  auto edge=new Edge[](0);
  foreach(_; 0..m){
    int a, b; rd(a, b);
    edge~=Edge(a-1, b-1);
  }

  int cnt=0;
  foreach(i; 0..m){
    auto uf=new UF(n);
    foreach(j; 0..m){
      if(i==j) continue;
      uf.unite(edge[j][0], edge[j][1]);
    }
    if(!uf.same(edge[i][0], edge[i][1])) cnt++;
  }
  writeln(cnt);
}


void rd(T...)(ref T x){
  import std.stdio, std.string, std.conv;
  auto l=readln.split;
  foreach(i, ref e; x){
    e=l[i].to!(typeof(e));
  }
}