#include <bits/stdc++.h> 

using namespace std;
using ll=long long;
using ull=unsigned long long;
using pii=pair<int,int>;

#define INF LONG_MAX
#define MOD 1000000007
#define rng(a) a.begin(),a.end()
#define rrng(a) a.end(),a.begin()

struct UF{
  vector<int>par,rank;
  UF(int n){
    par.resize(n);
    rank.resize(n,0);
    for(int i=0;i<n;i++)par[i]=i;
  }
  int root(int x){
    if(par[x]==x)return x;
    return par[x]=root(par[x]);
  }
  void unite(int x,int y){
    x=root(x);
    y=root(y);
    if(rank[x]<rank[y]){
      par[y]=x;
    }
    else{
      par[x]=y;
      if(rank[x]==rank[y]){
        rank[x]++;
      }
    }
  }
  bool isSame(int x,int y){
    return root(x)==root(y);
  }
};

struct Edge{
  int to,from,cost;
  bool operator<(Edge& o){
    return cost < o.cost;
  }
};

struct Graph{
  int n;
  vector<Edge> es;
  Graph(vector<Edge>es_,int n_){
    es=es_;
    n=n_;
  }
  int Kruskal(){
    sort(es.begin(),es.end());
    UF uf(n);
    int min_cost=0;
    int sum=0;
    for(int i=0;i<es.size();i++){
      Edge e=es[i];
      if(!uf.isSame(e.to,e.from)){
        sum++;
        min_cost+=e.cost;
        uf.unite(e.to,e.from);
      }
    }
    return sum;
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);

  int N,M;
  cin>>N>>M;
  vector<Edge>e(M);
  for(int i=0;i<M;i++)cin>>e[i].to>>e[i].from>>e[i].cost;
  Graph g(e,N);
  cout<<M-g.Kruskal()<<endl;
  return 0;
}
