#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
struct Edge {
  int src, dest, rev;
  int cap;
  int cost;
  bool operator<(const Edge &rhs) const { return cost > rhs.cost; }
  Edge(int s, int d) : src(s), dest(d) { ; }
  Edge(int s, int d, int c) : src(s), dest(d), cost(c) { ; }
  Edge(int s, int d, int r, int cp, int cst)
      : src(s), dest(d), rev(r), cap(cp), cost(cst) {
    ;
  }
};
vector<int> dijkstra(const vector<vector<Edge>> &g, int s) {
  int n = g.size();
  vector<int> d(n, INF);
  d[s] = 0;
  priority_queue<Edge> que;
  que.push(Edge(-1, s, 0));
  while (!que.empty()) {
    Edge e = que.top();
    que.pop();
    if (d[e.dest] < e.cost) continue;
    for (Edge f : g[e.dest]) {
      if (d[f.dest] > e.cost + f.cost) {
        d[f.dest] = e.cost + f.cost;
        que.push(Edge(f.src, f.dest, d[f.dest]));
      }
    }
  }
  return d;
}
int main() {
  int N, M;
  cin >> N >> M;
  vector<int> a(M), b(M), c(M);
  for (int i = 0; i < (int)(M); i++) {
    cin >> a[i] >> b[i] >> c[i];
    --a[i];
    --b[i];
  }
  vector<vector<Edge>> g(N);
  for (int i = 0; i < (int)(M); i++) {
    g[a[i]].push_back(Edge(a[i], b[i], c[i]));
    g[b[i]].push_back(Edge(b[i], a[i], c[i]));
  }
  vector<vector<int>> d(N);
  for (int i = 0; i < (int)(N); i++) d[i] = dijkstra(g, i);
  int res = 0;
  for (int i = 0; i < (int)(M); i++) {
    vector<vector<Edge>> gtmp(N);
    for (int j = 0; j < (int)(M); j++)
      if (j != i) {
        gtmp[a[j]].push_back(Edge(a[j], b[j], c[j]));
        gtmp[b[j]].push_back(Edge(b[j], a[j], c[j]));
      }
    bool flag = true;
    for (int j = 0; j < (int)(N); j++) {
      if (!flag) continue;
      vector<int> dtmp = dijkstra(gtmp, j);
      for (int k = 0; k < (int)(N); k++)
        if (dtmp[k] != d[j][k]) {
          flag = false;
          break;
        }
    }
    if (flag) ++res;
  }
  cout << res << endl;
  return 0;
}
