#include <bits/stdc++.h>
using namespace std;
int N, M;
int cost[101][101];
bool used_cost[101][101];
int d[101];
bool used[101];
int pv[101];
const int INF = 1e9 + 7;
bool ans[101];
void dijkstra(int s) {
  fill(d, d + N, INF);
  fill(used, used + N, false);
  fill(pv, pv + N, -1);
  d[s] = 0;
  while (true) {
    int v = -1;
    for (int(u) = (0); (u) < (int)(N); ++(u)) {
      if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
    }
    if (v == -1) break;
    used[v] = true;
    for (int(u) = (0); (u) < (int)(N); ++(u)) {
      if (d[u] > d[v] + cost[v][u]) {
        d[u] = d[v] + cost[v][u];
        pv[u] = v;
      }
    }
  }
}
void get_path(int t) {
  int a = -1, b = t;
  for (; t != -1; t = pv[t]) {
    b = t;
    if (a != -1 && b != -1) {
      used_cost[a][b] = true;
      used_cost[b][a] = true;
    }
    a = b;
  }
}
int main() {
  cin >> N >> M;
  fill(ans, ans + N, false);
  vector<pair<int, int>> m(M);
  for (int(i) = (0); (i) < (int)(M); ++(i)) {
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    m[i] = {a, b};
    cost[a][b] = c;
    cost[b][a] = c;
  }
  for (int(i) = (0); (i) < (int)(N); ++(i)) {
    dijkstra(i);
    for (int(j) = (0); (j) < (int)(N); ++(j)) {
      if (i != j) get_path(j);
    }
  }
  int c = 0;
  for (int(i) = (0); (i) < (int)(M); ++(i)) {
    if (!used_cost[m[i].first][m[i].second] &&
        !used_cost[m[i].second][m[i].first])
      c++;
  }
  cout << c << endl;
  return 0;
}
