#include <bits/stdc++.h>
template <class T>
inline T chmax(T& a, const T b) {
  return a = (a < b) ? b : a;
}
template <class T>
inline T chmin(T& a, const T b) {
  return a = (a > b) ? b : a;
}
using ll = long long;
using ull = unsigned long long;
using ld = long double;
constexpr ll MOD = 1000000007;
constexpr ll INF = 1e18;
using namespace std;
vector<ll> dijkstra(ll i, ll n, vector<vector<pair<ll, ll>>> graph) {
  vector<ll> d(n, INF);
  d[i] = 0;
  priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
  q.push(make_pair(0, i));
  while (!q.empty()) {
    pair<ll, ll> p = q.top();
    q.pop();
    ll v = p.second;
    if (d[v] < p.first) {
      continue;
    }
    for (auto x : graph[v]) {
      if (d[x.first] > d[v] + x.second) {
        d[x.first] = d[v] + x.second;
        q.push(pair<ll, ll>(d[x.first], x.first));
      }
    }
  }
  return d;
}
signed main() {
  ll N, M;
  cin >> N >> M;
  vector<vector<pair<ll, ll>>> graph(N);
  ll a, b, c;
  for (ll i = 0; i < ll(M); ++i) {
    cin >> a >> b >> c;
    a--;
    b--;
    graph[a].push_back(make_pair(b, c));
  }
  vector<vector<ll>> dist(N, vector<ll>(N));
  for (ll i = 0; i < ll(N); ++i)
    for (ll j = 0; j < ll(N); ++j) dist[i][j] = (i == j) ? 0 : INF;
  for (ll i = 0; i < ll(N); ++i) dist[i] = dijkstra(i, N, graph);
  ll ans = M;
  for (ll i = 0; i < ll(N); ++i) {
    for (ll j = 0; j < ll(graph[i].size()); ++j) {
      bool shortest = false;
      for (ll k = 0; k < ll(N); ++k)
        if (dist[k][i] + graph[i][j].second == dist[k][graph[i][j].first])
          shortest = true;
      if (shortest) ans--;
    }
  }
  cout << ans << endl;
  return 0;
}
