#include <bits/stdc++.h>
using namespace std;
const int INF = (int)1e8;
const int MAX_V = 101;
struct edge {
  int to;
  int cost;
  bool flag;
};
using P = pair<int, int>;
int d[MAX_V];
int previous[MAX_V];
bool used[MAX_V][MAX_V];
vector<edge> G[MAX_V];
void dijkstra(int s, int N, int M) {
  fill(d, d + MAX_V, INF);
  fill(previous, previous + MAX_V, -1);
  d[s] = 0;
  priority_queue<P, vector<P>, greater<P>> que;
  que.push(P(0, s));
  while (!que.empty()) {
    P p = que.top();
    que.pop();
    int v = p.second;
    if (d[v] < p.first) {
      continue;
    }
    for (auto e : G[v]) {
      if (d[e.to] > d[v] + e.cost) {
        d[e.to] = d[v] + e.cost;
        previous[e.to] = v;
        que.push(P(d[e.to], e.to));
      }
    }
  }
  for (int i = 1; i <= N; i++) {
    if (i == s) continue;
    vector<int> route;
    for (int ii = i; ii != -1; ii = previous[ii]) {
      route.push_back(ii);
    }
    for (int ii = (int)route.size() - 1; ii > 0; ii--) {
      used[route[ii]][route[ii - 1]] = true;
      used[route[ii - 1]][route[ii]] = true;
    }
  }
  for (int i = 1; i <= N; i++) {
    for (auto& e : G[i]) {
      if (used[i][e.to]) {
        e.flag = true;
      }
    }
  }
}
using namespace std;
int main() {
  int N, M;
  cin >> N >> M;
  int a, b, c;
  int ans;
  for (int i = 0; i < M; i++) {
    cin >> a >> b >> c;
    edge e = {b, c, false};
    G[a].push_back(e);
    e = {a, c, false};
    G[b].push_back(e);
  }
  for (int i = 0; i < N; i++) {
    dijkstra(i + 1, N, M);
  }
  ans = 0;
  for (int i = 1; i <= M; i++) {
    for (auto e : G[i]) {
      if (e.flag == false) {
        ans++;
      }
    }
  }
  ans = ans / 2;
  cout << ans << endl;
  return 0;
}
