#include <bits/stdc++.h>
using namespace std;
int N, M;
vector<vector<int> > edges;
set<pair<int, int> > used;
struct compless {
  bool operator()(pair<int, int> &a, pair<int, int> &b) {
    return a.second < b.second;
  }
};
void dijkstra(int u) {
  vector<int> costs;
  priority_queue<pair<int, int> > q;
  q.push(make_pair((u), (0)));
  costs.resize(N, 99999999);
  costs[u] = 0;
  while (!q.empty()) {
    pair<int, int> next = q.top();
    q.pop();
    for (int(n) = 0; (n) < (int)(N); ++(n)) {
      if (next.second + edges[next.first][n] < costs[n]) {
        costs[n] = next.first + edges[next.first][n];
        q.push(make_pair((n), (costs[n])));
      }
    }
  }
  for (int(s) = 0; (s) < (int)(N); ++(s)) {
    for (int(t) = 0; (t) < (int)(N); ++(t)) {
      int edgecost = edges[s][t];
      if (edgecost != 99999999) {
        0 && cout << "costs[" << s << "]==" << costs[s] << endl;
        0 && cout << "costs[" << t << "]==" << costs[t] << endl;
        0 && cout << "edgecost==" << edgecost << endl;
        if (costs[s] + edgecost == costs[t]) {
          int a = min(s, t);
          int b = max(s, t);
          0 && cout << "used.insert(" << a << "," << b << ")" << endl;
          used.insert(make_pair((a), (b)));
        }
      }
    }
  }
}
int main(int argc, char *argv[]) {
  ios::sync_with_stdio(false);
  cin >> N >> M;
  edges.resize(N);
  for (int(m) = 0; (m) < (int)(M); ++(m)) {
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    if (edges[a].size() == 0) {
      edges[a].resize(N, 99999999);
    }
    if (edges[b].size() == 0) {
      edges[b].resize(N, 99999999);
    }
    edges[a][b] = c;
    edges[b][a] = c;
  }
  for (int(n) = 0; (n) < (int)(N); ++(n)) {
    0 && cout << "[dijkstra] n=" << n << endl;
    dijkstra(n);
  }
  int ans = M - used.size();
  cout << ans << endl;
  return 0;
}
