#include <bits/stdc++.h>
using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pli = pair<ll, int>;
using pil = pair<int, ll>;
using pll = pair<ll, ll>;
template <typename T>
using vec = vector<T>;
using vi = vec<int>;
using vl = vec<ll>;
template <typename T>
using que = queue<T>;
template <typename T>
using deq = deque<T>;
template <typename T>
T id(T b) {
  return b;
};
template <typename T>
void chmax(T &x, T y) {
  if (x < y) x = y;
}
template <typename T>
void chmin(T &x, T y) {
  if (x > y) x = y;
}
template <typename S, typename K>
bool contains(S s, K k) {
  return s.find(k) != s.end();
}
void fastio() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
}
constexpr ll TEN(int n) {
  if (n == 0)
    return 1LL;
  else
    return 10LL * TEN(n - 1);
}
struct edge {
  int to, cost;
  size_t idx;
};
int n, m;
vec<edge> g[100];
bool used[1001];
int main() {
  fastio();
  cin >> n >> m;
  for (size_t i = 0; i < size_t(m); i++) {
    int a, b, c;
    cin >> a >> b >> c;
    a--, b--;
    g[a].push_back({b, c, i});
    g[b].push_back({a, c, i});
  }
  using elem = tuple<int, int, int>;
  for (size_t i = 0; i < size_t(n); i++) {
    vec<int> d(n, 1000 * 1000);
    d[i] = 0;
    deq<elem> q({(elem){0, i, 1000}});
    while (!q.empty()) {
      auto p = q.front();
      q.pop_front();
      int cost, i, idx;
      tie(cost, i, idx) = p;
      if (cost > d[i]) {
        continue;
      }
      used[idx] = true;
      d[i] = cost;
      for (edge e : g[i]) {
        if (d[e.to] >= d[i] + e.cost) {
          d[e.to] = d[i] + e.cost;
          q.emplace_back(d[e.to], e.to, e.idx);
        }
      }
    }
  }
  cout << count(used, used + m, false) << endl;
  return 0;
}
