#include <bits/stdc++.h>
#pragma GCC optimize("O3", "unroll-loops")
using namespace std;
using pii = pair<long long, long long>;
template <typename T>
using prior = priority_queue<T, vector<T>, greater<T>>;
template <typename T>
using Prior = priority_queue<T>;
const long long INF = 1E18;
const long long mod = 1E9 + 7;
const long long maxn = 100 + 5;
const long long maxm = 1000 + 5;
vector<pii> adj[maxn];
long long vis[maxn], dis[maxn], fl[maxn];
void dijkstra(long long now) {
  memset(vis, 0x00, sizeof(vis));
  memset(dis, 0x7f, sizeof(dis));
  dis[now] = 0;
  prior<pii> pq;
  pq.push({0, now});
  while (!pq.empty()) {
    now = pq.top().second;
    pq.pop();
    if (vis[now]) continue;
    vis[now] = 1;
    for (auto x : adj[now]) {
      if (vis[x.first]) continue;
      if (dis[x.first] > dis[now] + x.second)
        pq.push({dis[x.first] = dis[now] + x.second, x.first});
    }
  }
}
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  long long n, m, a, b, c, ans;
  cin >> n >> m, ans = m;
  tuple<long long, long long, long long> edge[m];
  for (long long i = 0; i < m; ++i) {
    cin >> a >> b >> c, edge[i] = make_tuple(a, b, c);
    adj[a].emplace_back(b, c), adj[b].emplace_back(a, c);
  }
  for (long long i = 1; i <= n; ++i) {
    dijkstra(i);
    for (long long j = 0; j < m; ++j) {
      if (fl[j]) continue;
      if (abs(dis[get<0>(edge[j])] - dis[get<1>(edge[j])]) == get<2>(edge[j]))
        fl[j] = 1, --ans;
    }
  }
  cout << ans << "\n";
  return 0;
}
