#include <bits/stdc++.h>
const long long MOD = 1e9 + 7;
const long long INF = 1e10 + 1;
using namespace std;
int dy[] = {1, -1, 0, 0, 1, 1, -1, -1, 0};
int dx[] = {0, 0, 1, -1, 1, -1, 1, -1, 0};
long long N, M, T;
bool used_side[105][105];
long long len[105][105];
vector<vector<long long>> adj;
vector<long long> A;
vector<long long> d;
void dijkstra(long long st) {
  priority_queue<tuple<long long, long long, long long>> PQ;
  vector<bool> used(N);
  for (long long i = 0; i < N; i++) {
    d[i] = INF;
    used[i] = false;
  }
  d[st] = 0;
  PQ.push(make_tuple(0, st, 0));
  while (!PQ.empty()) {
    tuple<long long, long long, long long> f = PQ.top();
    PQ.pop();
    long long u = get<1>(f);
    if (d[u] < get<0>(f) * (-1)) continue;
    long long before = get<2>(f);
    used_side[u][before] = true;
    used_side[before][u] = true;
    for (long long j = 0; j < adj[u].size(); j++) {
      long long v = adj[u][j];
      if (used[v]) continue;
      if (len[u][v] == -1) continue;
      if (d[v] > d[u] + len[u][v]) {
        d[v] = d[u] + len[u][v];
        PQ.push(make_tuple(d[v] * (-1), v, u));
      }
    }
  }
}
int main() {
  cin >> N >> M;
  d = vector<long long>(N);
  adj = vector<vector<long long>>(N);
  A = vector<long long>(N);
  vector<long long> dis(N), st(N), en(N);
  for (long long i = 0; i < N; i++) {
    for (long long j = 0; j < N; j++) {
      len[i][j] = -1;
      used_side[i][j] = false;
    }
  }
  for (long long i = 0; i < M; i++) {
    long long a, b, c;
    cin >> a >> b >> c;
    a--, b--;
    adj[a].push_back(b);
    adj[b].push_back(a);
    len[a][b] = c;
    len[b][a] = c;
  }
  for (long long i = 0; i < N; i++) {
    dijkstra(i);
  }
  long long ans = 0;
  for (long long i = 0; i < N; i++) {
    for (long long j = 0; j < N; j++) {
      if (i == j) continue;
      if (!used_side[i][j]) ans++;
    }
  }
  ans /= 2;
  cout << ans << endl;
}
