#include <bits/stdc++.h>
using namespace std;
vector<vector<tuple<int, int>>> e;
map<tuple<int, int>, bool> mp;
const int INF = (int)1e9;
struct Dijkstra {
  int n;
  vector<int> d;
  vector<int> prev;
  Dijkstra(int x) {
    n = x;
    d = vector<int>(x + 1, INF);
    prev = vector<int>(x + 1);
  }
  void calc(int s) {
    d[s] = 0;
    priority_queue<tuple<int, int>, vector<tuple<int, int>>,
                   greater<tuple<int, int>>>
        q;
    q.push(make_tuple(0, s));
    while (!q.empty()) {
      int dist, from;
      tie(dist, from) = q.top();
      q.pop();
      if (dist > d[from]) continue;
      for (int i = 0; i < e[from].size(); i++) {
        int to, c;
        tie(to, c) = e[from][i];
        if (d[from] + c < d[to]) {
          d[to] = d[from] + c;
          q.push(make_tuple(to, d[to]));
          prev[to] = from;
        }
      }
    }
  }
  void edge_check() {
    for (int i = 1; i <= n; i++) {
      int now = i, p = prev[i];
      if (p == 0) continue;
      if (now < p) {
        mp[make_tuple(now, p)] = true;
      } else {
        mp[make_tuple(p, now)] = true;
      }
    }
  }
};
int main() {
  int n, m, ans = 0;
  cin >> n >> m;
  e = vector<vector<tuple<int, int>>>(n + 1, vector<tuple<int, int>>());
  for (int i = 0; i < m; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    e[a].emplace_back(b, c);
    e[b].emplace_back(a, c);
    if (a < b)
      mp[make_tuple(a, b)] = false;
    else
      mp[make_tuple(b, a)] = false;
  }
  for (int i = 1; i <= n; i++) {
    Dijkstra g(n);
    g.calc(i);
    g.edge_check();
  }
  for (auto&& i : mp) {
    if (i.second == false) ans++;
  }
  cout << ans << endl;
  return 0;
}
