#include <bits/stdc++.h>
#pragma gcc target("avx2")
#pragma gcc optimization("o3")
#pragma gcc optimization("unroll-loops")
using ll = long long;
constexpr int INF = 1073741823;
constexpr int MINF = -1073741823;
constexpr ll LINF = ll(4661686018427387903);
constexpr ll MOD = 1000000007;
const long double PI = acos(-1.0L);
using namespace std;
void scans(string& str) {
  char c;
  str = "";
  scanf("%c", &c);
  if (c == '\n') scanf("%c", &c);
  while (c != '\n' && c != -1) {
    str += c;
    scanf("%c", &c);
  }
}
void scanc(char& str) {
  char c;
  scanf("%c", &c);
  if (c == -1) return;
  while (c == '\n') {
    scanf("%c", &c);
  }
  str = c;
}
double acot(double x) { return PI / 2 - atan(x); }
ll gcd(ll a, ll b) {
  if (b == 0) return a;
  return gcd(b, a % b);
}
ll lcm(ll number1, ll number2) {
  return number1 / gcd(number1, number2) * number2;
}
ll LSB(ll n) { return (n & (-n)); }
template <typename T>
struct segtree {
  vector<T> seg, lazy;
  int siz;
  const T unit;
  using F = function<T(T, T)>;
  const F f;
  using F2 = function<T(T, T)>;
  const F2 f2;
  segtree(int n, const T a, const F f, const F2 f2) : unit(a), f(f), f2(f2) {
    siz = 1;
    while (siz < n) siz <<= 1;
    seg.assign(2 * siz - 1, unit);
    lazy.assign(2 * siz - 1, unit);
    --siz;
  }
  void set(int k, const T& t) { seg[k + siz] = t; }
  void build() {
    for (int i = siz - 1; i >= 0; --i)
      seg[i] = f(seg[i * 2 + 1], seg[i * 2 + 2]);
  }
  void eval(int k) {
    if (lazy[k] != unit) {
      seg[k] = f(seg[k], lazy[k]);
      if (k < siz) {
        lazy[(k << 1) + 1] = f2(lazy[k], lazy[(k << 1) + 1]);
        lazy[(k << 1) + 2] = f2(lazy[k], lazy[(k << 1) + 2]);
      }
    }
    lazy[k] = unit;
  }
  T operator[](const int i) { return seg[i + siz]; }
  void update(int k, T a) {
    k += siz;
    seg[k] = a;
    while (k > 0) {
      k = ((k - 1) >> 1);
      seg[k] = f(seg[k * 2 + 1], seg[k * 2 + 2]);
    }
  }
  void update(int l, int r, T a) {}
  T query(int a, int b) {
    T l = unit, r = unit;
    for (a += siz, b += siz; a < b; a >>= 1, b >>= 1) {
      if (!(a & 1)) l = f(l, seg[a++]);
      if (!(b & 1)) r = f(seg[--b], r);
    }
    return f(l, r);
  }
  template <typename C>
  int find(const int start, const int end, int l, int r, int k, const C check,
           T& checknum, const bool b, const function<T(T, T)> revf) {
    if (start <= l && r <= end && !check(seg[k], checknum)) {
      checknum = revf(checknum, seg[k]);
      return -1;
    }
    if ((r <= start || l >= end)) {
      return -1;
    }
    if (k >= siz) {
      return k - siz;
    }
    int res;
    if (b) {
      res = find<C>(start, end, l, ((l + r) >> 1), (k << 1) + 1, check,
                    checknum, b, revf);
      if (res != -1) return (res);
      return find<C>(start, end, ((l + r) >> 1), r, (k << 1) + 2, check,
                     checknum, b, revf);
    } else {
      res = find<C>(start, end, ((l + r) >> 1), r, (k << 1) + 2, check,
                    checknum, b, revf);
      if (res != -1) return (res);
      return find<C>(start, end, l, ((l + r) >> 1), (k << 1) + 1, check,
                     checknum, b, revf);
    }
  }
  template <typename C>
  int find_left(int start, int end, const C check, T& checknum,
                function<T(T, T)> revf) {
    return find<C>(start, end, 0, siz + 1, 0, check, checknum, true, revf);
  }
  template <typename C>
  int find_right(int start, int end, const C check, T& checknum,
                 function<T(T, T)> revf) {
    return find<C>(start, end, 0, siz + 1, 0, check, checknum, false, revf);
  }
};
void WarshallFloyd(int n, vector<vector<int>>& d) {
  for (int i = 0; i < (n); ++i) {
    for (int j = 0; j < (n); ++j) {
      for (int k = 0; k < (n); ++k) {
        d[j][k] = min(d[j][k], d[j][i] + d[i][k]);
      }
    }
  }
}
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  int a, b, c;
  vector<vector<int>> graph(n, vector<int>(n)), cost(n, vector<int>(n)),
      g(n, vector<int>(n));
  vector<tuple<int, int, int>> ab(m);
  vector<vector<vector<int>>> cst(m, vector<vector<int>>(n, vector<int>(n)));
  for (int i = 0; i < (n); ++i) fill((graph[i]).begin(), (graph[i]).end(), INF);
  for (int i = 0; i < (m); ++i) {
    scanf("%d%d%d", &a, &b, &c);
    --a;
    --b;
    graph[a][b] = graph[b][a] = c;
    ab[i] = {a, b, c};
  }
  g = cost = graph;
  WarshallFloyd(n, cost);
  int ans = 0, cnt = 0;
  for (int i = 0; i < (m); ++i) {
    graph[get<0>(ab[i])][get<1>(ab[i])] = graph[get<1>(ab[i])][get<0>(ab[i])] =
        LINF;
    WarshallFloyd(n, graph);
    if (graph == cost) ++ans;
    cnt = 0;
    for (int j = 0; j < (i); ++j)
      if (graph == cst[j]) ++cnt;
    if (cnt == 1) --ans;
    graph = g;
  }
  printf("%d\n", ans);
  return 0;
}
