#include <bits/stdc++.h>
template <class T>
constexpr T inf = (T(1) << (8 * sizeof(T) - 3));
template <class Weight>
struct Edge {
  size_t src, dst;
  Weight cost;
  Edge(size_t src, size_t dst, Weight cost = 1)
      : src(src), dst(dst), cost(cost) {}
  bool operator<(const Edge<Weight> &rhs) const {
    if (cost != rhs.cost) return cost < rhs.cost;
    if (src != rhs.src) return src < rhs.src;
    return dst < rhs.dst;
  }
};
template <class Weight>
using Graph = std::vector<std::vector<Edge<Weight>>>;
int main() {
  size_t N, M;
  scanf("%zu %zu", &N, &M);
  std::vector<std::vector<int>> g(N, std::vector<int>(N, inf<int>));
  for (size_t i = 0; i < N; ++i) g[i][i] = 0;
  std::vector<Edge<int>> es;
  for (size_t i = 0; i < M; ++i) {
    size_t a, b;
    int c;
    scanf("%zu %zu %d", &a, &b, &c);
    --a;
    --b;
    g[a][b] = g[b][a] = c;
    es.emplace_back(a, b, c);
  }
  std::vector<std::vector<int>> d = g;
  for (size_t k = 0; k < N; ++k)
    for (size_t i = 0; i < N; ++i)
      for (size_t j = 0; j < N; ++j)
        d[i][j] = std::min(d[i][j], d[i][k] + d[k][j]);
  auto is_cand = [&](const Edge<int> &e) -> bool {
    for (size_t i = 0; i < N; ++i)
      for (size_t j = i + 1; j < N; ++j)
        if (d[i][e.src] + e.cost + d[e.dst][j] == d[i][j]) return true;
    return false;
  };
  int res = M;
  for (const auto &e : es)
    if (is_cand(e)) --res;
  printf("%d\n", res);
}
