#include <bits/stdc++.h>
using namespace std;
const int TMAX = INT_MAX;
int startA = 0;
vector<int> goAry;
vector<int> gone;
struct edge {
  int a;
  int cost;
  edge(){};
  edge(int a, int cost) : a(a), cost(cost) {}
  bool operator>(const edge &edge) const { return cost > edge.cost; }
};
vector<vector<edge> > goList;
vector<vector<edge> > roundTripList;
map<pair<int, int>, int> mpi;
void dijkstra(vector<vector<edge> > &list, vector<int> &ary) {
  ary[startA] = 0;
  priority_queue<edge, vector<edge>, greater<edge> > que;
  que.push(edge(startA, 0));
  gone[startA] = 0;
  while (!que.empty()) {
    edge a = que.top();
    que.pop();
    if (ary[a.a] < a.cost) continue;
    for (int i = 0; i < (signed)list[a.a].size(); i++) {
      edge e = list[a.a][i];
      if (gone[e.a] == -1) {
        if (ary[e.a] > ary[a.a] + e.cost) {
          ary[e.a] = ary[a.a] + e.cost;
          que.push(edge(e.a, ary[e.a]));
        }
        gone[e.a] = 0;
      }
    }
  }
  return;
}
int main() {
  int N, M;
  if (scanf("%d%d", &N, &M) < 2) return 0;
  goAry.resize(N);
  gone.resize(N);
  goList.resize(N);
  roundTripList.resize(2 * M);
  for (int i = 0; i < M; i++) {
    int a, b, c;
    if (scanf("%d%d%d", &a, &b, &c) < 3) return 0;
    a--;
    b--;
    goList[a].push_back(edge(b, c));
    roundTripList[a].push_back(edge(b, c));
    roundTripList[b].push_back(edge(a, c));
  }
  for (int i = 0; i < N; i++) {
    goAry[i] = TMAX;
    gone[i] = -1;
  }
  for (int i = 0; i < N; i++) {
    startA = i;
    dijkstra(roundTripList, goAry);
    for (int j = 0; j < N; j++) {
      for (int k = 0; k < (signed)goList[j].size(); k++) {
        int fromA = j;
        int toA = goList[j][k].a;
        if (goAry[fromA] + goList[j][k].cost != goAry[toA]) {
          mpi[make_pair(fromA, toA)]++;
        }
      }
    }
  }
  int cnt = 0;
  for (pair<pair<int, int>, int> p : mpi) {
    if (p.second == N) cnt++;
  }
  printf("%d\n", cnt);
  return 0;
}
