#include <bits/stdc++.h>
using namespace std;
const long long INF = 1LL << 60;
const long long MOD = 1000000000 + 7;
struct Edge {
  int to;
  int weight;
  Edge(int t, int w) : to(t), weight(w) {}
};
using Graph = vector<vector<Edge>>;
long long cost[101];
long long cost_g;
Graph G(101);
void dfs(int from, int goal, bool &res, set<pair<int, int>> &path) {
  if (from == goal) {
    if (cost[from] < cost_g) {
      cost_g = cost[from];
      path.clear();
    }
    res = true;
    return;
  }
  for (int i = 0; i < (int)(G[from].size()); i++) {
    int next = G[from][i].to;
    int w = G[from][i].weight;
    if (cost[from] + w <= cost[next]) {
      cost[next] = cost[from] + w;
      dfs(next, goal, res, path);
      if (res) {
        path.insert({from, next});
        continue;
      }
    }
    res = false;
  }
  return;
}
int main() {
  int n, m;
  cin >> n >> m;
  set<pair<int, int>> edge;
  for (int i = 0; i < (int)(m); i++) {
    int a, b, c;
    cin >> a >> b >> c;
    G[a].push_back(Edge(b, c));
    G[b].push_back(Edge(a, c));
    edge.insert({a, b});
  }
  for (int stt = 1; stt <= n; stt++) {
    for (int goal = stt + 1; goal < n + 1; goal++) {
      for (int k = 0; k < (int)(n + 1); k++) cost[k] = INF;
      cost[stt] = 0;
      cost_g = INF;
      set<pair<int, int>> path;
      bool reach;
      dfs(stt, goal, reach, path);
      for (auto itr = path.begin(); itr != path.end(); itr++) {
        edge.erase({itr->first, itr->second});
        edge.erase({itr->second, itr->first});
      }
    }
  }
  cout << edge.size() << endl;
  return 0;
}
