#include <bits/stdc++.h>
using namespace std;
inline int toInt(string s) {
  int v;
  istringstream sin(s);
  sin >> v;
  return v;
}
template <class T>
inline string toString(T x) {
  ostringstream sout;
  sout << x;
  return sout.str();
}
template <class T>
inline T sqr(T x) {
  return x * x;
}
const double EPS = 1e-10;
const double PI = acos(-1.0);
template <class T>
inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
int main(void) {
  int N, M;
  cin >> N >> M;
  int a[M], b[M], c[M];
  map<int, vector<pair<int, int>>> e;
  set<pair<int, int>> cand;
  for (int i = (0); i < (M); ++i) {
    cin >> a[i] >> b[i] >> c[i];
    a[i]--;
    b[i]--;
    e[a[i]].push_back(make_pair(b[i], c[i]));
    e[b[i]].push_back(make_pair(a[i], c[i]));
    cand.insert(make_pair(min(a[i], b[i]), max(a[i], b[i])));
  }
  for (int i = (0); i < (N); ++i) {
    vector<int> done(N, 0);
    set<pair<int, pair<int, int>>> nex;
    for (auto n : e[i]) {
      nex.insert(make_pair(n.second, make_pair(i, n.first)));
    }
    done[i] = 1;
    while (!nex.empty()) {
      auto top = nex.begin();
      auto node = *top;
      nex.erase(node);
      int from = node.second.first, to = node.second.second, d = node.first;
      if (done[to] == 1) continue;
      done[to] = 1;
      cand.erase(make_pair(min(from, to), max(from, to)));
      for (auto n : e[to]) {
        nex.insert(make_pair(n.second, make_pair(to, n.first)));
      }
    }
  }
  cout << cand.size() << endl;
  return 0;
}
