#include <bits/stdc++.h>
template <class T>
bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
using namespace std;
int used[101][101];
struct edge {
  int to, cost;
};
struct dijkstra {
  using P = pair<int, int>;
  priority_queue<P, vector<P>, greater<P>> q;
  vector<vector<edge>> ed;
  vector<int> dist;
  int sz;
  dijkstra(int size) {
    sz = size;
    ed.resize(size);
  }
  void reset() {
    dist.assign(sz, -1);
    q = priority_queue<P, vector<P>, greater<P>>();
  }
  void ae(int from, int to, int cost) { ed[from].push_back({to, cost}); }
  int cal(int start, int end) {
    reset();
    q.push({0, start});
    while (!q.empty()) {
      P tp = q.top();
      q.pop();
      int from = tp.second % 1000;
      tp.second /= 1000;
      if (dist[tp.second] != -1) continue;
      dist[tp.second] = tp.first;
      used[from][tp.second] = 1;
      used[tp.second][from] = 1;
      for (auto nn : ed[tp.second]) {
        if (dist[nn.to] != -1) continue;
        q.push({nn.cost + tp.first, nn.to * 1000 + tp.second});
      }
    }
    return dist[end];
  }
  int getd(int end) { return dist[end]; }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  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]--;
    used[a[i]][b[i]] = 2;
    used[b[i]][a[i]] = 2;
  }
  for (int i = 0; i < (int)(n); i++) {
    dijkstra dj(n);
    for (int j = 0; j < (int)(m); j++) {
      dj.ae(a[j], b[j], c[j]);
      dj.ae(b[j], a[j], c[j]);
    }
    dj.cal(i, n - 1);
  }
  int cnt = 0;
  for (int i = 0; i < (int)(101); i++)
    for (int j = int(i + 1); j < int(101); j++)
      if (used[i][j] == 2) {
        cnt++;
      }
  cout << cnt << endl;
  return 0;
}
