#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,m,n) for(int i=(m);i<(n);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
using ll = long long;
template <typename T> using posteriority_queue = priority_queue<T, vector<T>, greater<T> >;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3fLL;
const double EPS = 1e-8;
const int MOD = 1000000007;
// const int MOD = 998244353;
const int dy[] = {1, 0, -1, 0}, dx[] = {0, -1, 0, 1};
const int dy8[] = {1, 1, 0, -1, -1, -1, 0, 1}, dx8[] = {0, -1, -1, -1, 0, 1, 1, 1};
template <typename T, typename U> inline bool chmax(T &a, U b) { return a < b ? (a = b, true) : false; }
template <typename T, typename U> inline bool chmin(T &a, U b) { return a > b ? (a = b, true) : false; }
template <typename T> void unique(vector<T> &a) { a.erase(unique(ALL(a)), a.end()); }
struct IOSetup {
  IOSetup() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(20);
  }
} iosetup;

template <typename T>
struct WarshallFloyd {
  vector<vector<T> > graph, dist;

  WarshallFloyd(const vector<vector<T> > &graph, const T TINF) : graph(graph), dist(graph), TINF(TINF) {
    n = graph.size();
    internal.assign(n, vector<int>(n, -1));
    REP(k, n) REP(i, n) REP(j, n) {
      if (dist[i][j] > dist[i][k] + dist[k][j]) {
        dist[i][j] = dist[i][k] + dist[k][j];
        internal[i][j] = k;
      }
    }
  }

  void add(int src, int dst, T cost) {
    srcs.emplace_back(src);
    dsts.emplace_back(dst);
    costs.emplace_back(cost);
  }

  void calc() {
    set<int> vers;
    int sz = srcs.size();
    REP(i, sz) {
      int s = srcs[i], t = dsts[i];
      T cost = costs[i];
      chmin(graph[s][t], cost);
      if (dist[s][t] >= cost) {
        dist[s][t] = cost;
        internal[s][t] = -1;
      }
      vers.emplace(s);
      vers.emplace(t);
    }
    for (int v : vers) {
      REP(i, n) REP(j, n) {
        if (dist[i][j] > dist[i][v] + dist[v][j]) {
          dist[i][j] = dist[i][v] + dist[v][j];
          internal[i][j] = v;
        }
      }
    }
    srcs.clear();
    dsts.clear();
    costs.clear();
  }

  bool has_negative_cycle() {
    REP(i, n) {
      if (dist[i][i] < 0) return true;
    }
    return false;
  }

  vector<int> build_path(int s, int t) {
    vector<int> res;
    if (dist[s][t] != TINF) {
      build_path(s, t, res);
      res.emplace_back(t);
    }
    return res;
  }

private:
  const T TINF;
  int n;
  vector<vector<int> > internal;
  vector<int> srcs, dsts;
  vector<T> costs;

  void build_path(int s, int t, vector<int> &path) {
    int k = internal[s][t];
    if (k == -1) {
      path.emplace_back(s);
    } else {
      build_path(s, k, path);
      build_path(k, t, path);
    }
  }
};


int main() {
  int n, m; cin >> n >> m;
  vector<vector<int> > graph(n, vector<int>(n, INF));
  REP(i, n) graph[i][i] = 0;
  vector<int> a(m), b(m), c(m);
  REP(i, m) {
    cin >> a[i] >> b[i] >> c[i]; --a[i]; --b[i];
    chmin(graph[a[i]][b[i]], c[i]);
    chmin(graph[b[i]][a[i]], c[i]);
  }
  WarshallFloyd<int> wf(graph, INF);
  int ans = 0;
  REP(i, m) ans += wf.dist[a[i]][b[i]] != c[i];
  cout << ans << '\n';
  return 0;
}


Measured memory_bytes: 384