#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using P = pair<int, int>;
struct edge_ {
  int fr, to, we;
  bool operator<(const edge_& o) const { return we > o.we; }
};
class UnionFind {
 public:
  vector<ll> par;
  UnionFind(ll size) : par(size, -1) {}
  bool unite(ll x, ll y) {
    x = root(x), y = root(y);
    if (x == y) return false;
    if (par[y] < par[x]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
  bool find(ll x, ll y) { return root(x) == root(y); }
  ll root(ll x) { return par[x] < 0 ? x : par[x] = root(par[x]); }
  ll size(ll x) { return -par[root(x)]; }
};
int main() {
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  vector<edge_> w;
  vector<vector<int>> d(n, vector<int>(n, 1 << 30));
  {
    priority_queue<edge_> que;
    for (ll i = 0; i < (ll)m; i++) {
      int a, b, c;
      cin >> a >> b >> c;
      a--, b--;
      que.push({a, b, c});
    }
    while (!que.empty()) {
      edge_ nv = que.top();
      que.pop();
      if (!uf.unite(nv.fr, nv.to)) {
        w.push_back(nv);
        continue;
      }
      d[nv.fr][nv.to] = d[nv.to][nv.fr] = nv.we;
    }
  }
  for (ll i = 0; i < (ll)n; i++) d[i][i] = 0;
  for (ll K = 0; K < (ll)n; K++)
    for (ll i = 0; i < (ll)n; i++)
      for (ll j = 0; j < (ll)n; j++) d[i][j] = min(d[i][j], d[i][K] + d[K][j]);
  ll res = n - 1;
  for (ll i = 0; i < (ll)w.size(); i++)
    if (w[i].we <= d[w[i].fr][w[i].to]) res++;
  cout << m - res << endl;
  return 0;
}
