#include <bits/stdc++.h>
using namespace std;
const int MAXN = 128;
int log[MAXN][MAXN];
struct Edge {
  int src, dest, weight;
};
vector<vector<Edge> > g;
vector<int> trace;
inline bool operator<(const Edge &a, const Edge &b) {
  if (a.weight < b.weight) return true;
  if (a.weight > b.weight) return false;
  if (a.src < b.src) return true;
  if (a.src > b.src) return false;
  return a.dest < b.dest;
}
inline bool operator>(const Edge &a, const Edge &b) { return b < a; }
void shortest(int start) {
  int n = g.size();
  trace.assign(n, -2);
  priority_queue<Edge, vector<Edge>, greater<Edge> > q;
  q.push((Edge){-1, start, 0});
  while (!q.empty()) {
    Edge e = q.top();
    q.pop();
    if (trace[e.dest] >= 0) {
      if (trace[e.dest] < e.weight) continue;
    }
    trace[e.dest] = e.weight;
    int a = min(e.src, e.dest);
    int b = max(e.src, e.dest);
    if (a >= 0 && b >= 0) log[a][b] = log[b][a] = 2;
    for (vector<Edge>::iterator it = g[e.dest].begin(); it != g[e.dest].end();
         ++it) {
      int nw = e.weight + it->weight;
      if (trace[it->dest] == -2) {
        q.push((Edge){it->src, it->dest, e.weight + it->weight});
      } else {
        if (trace[it->dest] == nw) {
          q.push((Edge){it->src, it->dest, e.weight + it->weight});
        }
      }
    }
  }
}
int main() {
  int N, M;
  scanf("%d %d", &N, &M);
  for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++) log[i][j] = 0;
  g = vector<vector<Edge> >(N);
  for (int i = 0; i < M; i++) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    a--;
    b--;
    g[a].push_back((Edge){a, b, c});
    g[b].push_back((Edge){b, a, c});
    log[a][b] = log[b][a] = 1;
  }
  vector<int> cnt(3, 0);
  for (int s = 0; s < N; s++) {
    shortest(s);
  }
  for (int i = 0; i < N; i++) {
    for (int j = i + 1; j < N; j++) {
      cnt[log[i][j]]++;
    }
  }
  cout << cnt[1] << endl;
  return 0;
}
