#include <bits/stdc++.h>
using namespace std;
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& vec) {
  os << "[";
  for (const auto& v : vec) {
    os << v << ",";
  }
  os << "]";
  return os;
}
template <typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
  os << "(" << p.first << "," << p.second << ")";
  return os;
}
long long gcd(long long a, long long b) {
  if (b == 0)
    return a;
  else
    return gcd(b, a % b);
}
constexpr long long mod = 1e9 + 7;
const int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
class UnionFind {
 public:
  vector<int> rank, parent;
  UnionFind(int n) {
    rank.resize(n, 0);
    parent.resize(n, 0);
    for (int i = 0; i < n; i++) {
      parent[i] = i;
      rank[i] = 0;
    }
  }
  int find_root(int x) {
    if (parent[x] == x)
      return x;
    else
      return parent[x] = find_root(parent[x]);
  }
  void unite(int x, int y) {
    x = find_root(x);
    y = find_root(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      parent[x] = y;
    } else {
      parent[y] = x;
      if (rank[x] == rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y) { return find_root(x) == find_root(y); }
};
pair<int, pair<int, int>> makeP(int a, int b, int c) {
  return make_pair(a, make_pair(b, c));
}
int N, M;
int main() {
  cin >> N >> M;
  vector<vector<int>> g(N + 1, vector<int>(N + 1, 1 << 29));
  using P = pair<int, pair<int, int>>;
  vector<P> vp;
  for (int i = 0; i < M; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    g[a][b] = c;
    g[b][a] = c;
    vp.push_back(makeP(c, a, b));
  }
  sort((vp).begin(), (vp).end());
  UnionFind uf(N);
  int use = 0;
  for (auto p : vp) {
    int cost = p.first;
    int a = p.second.first;
    int b = p.second.second;
    if (uf.same(a, b)) continue;
    uf.unite(a, b);
    use++;
  }
  cout << M - use << endl;
}
