#include <bits/stdc++.h>
using namespace std;
const int INF = 1001001001;
template <typename T>
ostream& operator<<(ostream& s, const vector<T>& v) {
  int len = v.size();
  for (int i = 0; i < len; ++i) {
    s << v[i];
    if (i < len - 1) s << "\t";
  }
  return s;
}
int d[100][100];
int n, m;
void wf(const vector<tuple<int, int, int>>& edges) {
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      d[i][j] = INF;
    }
  }
  for (auto edge : edges) {
    int a, b, c;
    tie(a, b, c) = edge;
    d[a][b] = c;
    d[b][a] = c;
  }
  for (int k = 0; k < n; ++k) {
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
      }
    }
  }
}
bool removable(tuple<int, int, int>& edge) {
  int a, b, c;
  tie(a, b, c) = edge;
  for (int i = 0; i < n; ++i) {
    if (d[i][a] + c == d[b][i]) return false;
  }
  return true;
}
int main() {
  cin >> n >> m;
  vector<tuple<int, int, int>> edges;
  for (int i = 0; i < m; ++i) {
    int a, b, c;
    cin >> a >> b >> c;
    --a;
    --b;
    edges.emplace_back(a, b, c);
  }
  wf(edges);
  int ans = 0;
  for (int i = 0; i < m; ++i) {
    if (removable(edges[i])) ++ans;
  }
  cout << ans << endl;
}
