#include <bits/stdc++.h>
using namespace std;
const int INF = INT_MAX;
const long long INFL = (1LL << 40);
const int MOD = pow(10, 9) + 7;
int dy[] = {0, 0, 1, -1, 0};
int dx[] = {1, -1, 0, 0, 0};
template <typename T>
istream& operator>>(istream& is, vector<T>& vec) {
  for (T& x : vec) is >> x;
  return is;
}
template <typename T>
ostream& operator<<(ostream& os, vector<T>& vec) {
  for (int i = 0; i < vec.size(); i++) {
    os << vec[i] << (i + 1 == vec.size() ? "" : " ");
  }
  return os;
}
template <typename T>
struct edge {
  int src, to;
  T cost;
  edge(int to, T cost) : src(-1), to(to), cost(cost) {}
  edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}
  edge& operator=(const int& x) {
    to = x;
    return *this;
  }
  operator int() const { return to; }
};
template <typename T>
using Edges = vector<edge<T>>;
template <typename T>
using WeightedGraph = vector<Edges<T>>;
using UnWeightedGraph = vector<vector<int>>;
template <typename T>
using Matrix = vector<vector<T>>;
int N, M;
Matrix<int> d;
template <typename T>
void warshall_floyd(Matrix<T>& g, T INF) {
  for (int k = 0; k < g.size(); k++) {
    for (int i = 0; i < g.size(); i++) {
      for (int j = 0; j < g.size(); j++) {
        if (g[i][k] == INF || g[k][j] == INF) continue;
        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
      }
    }
  }
}
int main() {
  cin >> N >> M;
  d.resize(N);
  for (auto i = 0; i < N; i++) {
    d[i].resize(N);
  }
  int a, b, c;
  Edges<int> path;
  for (auto i = 0; i < M; i++) {
    cin >> a >> b >> c;
    a--;
    b--;
    d[a][b] = c;
    d[b][a] = c;
    path.emplace_back(a, b, c);
  }
  warshall_floyd(d, INF);
  set<edge<int>> stp;
  for (auto i = 0; i < M; i++) {
    int st = path[i].src;
    int t = path[i].to;
    int c = path[i].cost;
    for (auto s = 0; s < N; s++) {
      if (d[s][st] + c == d[s][t]) {
        stp.insert(path[i]);
      }
    }
  }
  cout << M - stp.size() << endl;
  return 0;
}
