#include <bits/stdc++.h>
using namespace std;
void ans(bool b) { cout << (b ? "Yes" : "No") << endl; }
void ans2(bool b) { cout << (b ? "YES" : "NO") << endl; }
template <typename T>
inline bool chmax(T& a, T b) {
  if (a < b) a = b;
  return a < b;
}
template <typename T>
inline bool chmin(T& a, T b) {
  if (b < a) a = b;
  return b < a;
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T& val) {
  fill((T*)array, (T*)(array + N), val);
}
template <typename T>
void vdeb(T v) {
  cout << "#vector set debug" << endl;
  for (auto vv : v) cout << vv << " ";
  cout << endl;
}
template <typename T1, typename T2>
void adeb(T1 arr[], T2 n) {
  cout << "#adebug" << endl;
  for (int i = 0; i <= n; i++) cout << arr[i] << " ";
  cout << endl;
}
template <typename T1>
void mdeb(T1 mp) {
  cout << "#map pair debug" << endl;
  for (auto const& m : mp) cout << m.first << " " << m.second << endl;
}
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, -1, 1};
template <typename T>
class WarshallFloyd {
 public:
  int n;
  vector<vector<T>> g;
  WarshallFloyd(int n, T mx) : n(n) {
    g.assign(n + 1, vector<T>(n + 1, mx));
    for (long long i = 0; i <= n; i++) {
      g[i][i] = 0;
    }
  }
  void add(int from, int to, long long cost) { g[from][to] = cost; }
  void build() {
    for (long long k = 1; k <= n; k++) {
      for (long long i = 1; i <= n; i++) {
        for (long long j = 1; j <= n; j++) {
          g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
        }
      }
    }
  }
  T result(int from, int to) { return g[from][to]; }
};
class DCandidatesOfNoShortestPaths {
 public:
  void solve(std::istream& in, std::ostream& out) {
    struct edge {
      int to, cost, id;
      edge(int to, int cost, int id) : to(to), cost(cost), id(id) {}
    };
    int n, m, a, b, c;
    in >> n >> m;
    WarshallFloyd<long long> wf(n, 1e18);
    vector<edge> g[110];
    for (long long i = 0; i < n; i++) {
      in >> a >> b >> c;
      wf.add(a, b, c);
      wf.add(b, a, c);
      g[a].push_back(edge(b, c, i));
      g[b].push_back(edge(a, c, i));
    }
    wf.build();
    vector<int> used;
    vector<int> visit(n + 1, 0);
    int dist;
    function<void(int, long long, vector<int>)> dfs = [&](int u, long long sum,
                                                          vector<int> edges) {
      if (u == dist) {
        used.insert(used.end(), edges.begin(), edges.end());
      }
      visit[u] = 1;
      for (auto const& e : g[u]) {
        if (visit[e.to]) continue;
        if (sum + e.cost > wf.result(u, e.to)) continue;
        edges.push_back(e.id);
        dfs(e.to, sum + e.cost, edges);
        edges.pop_back();
      }
    };
    for (long long i = 1; i <= n; i++) {
      for (long long j = 1; j <= n; j++) {
        visit.assign(n + 1, 0);
        dist = j;
        dfs(i, 0, vector<int>());
      }
    }
    set<int> res;
    for (auto const& e : used) {
      res.insert(e);
    }
    out << m - res.size() << endl;
  }
};
int main() {
  DCandidatesOfNoShortestPaths solver;
  std::istream& in(std::cin);
  std::ostream& out(std::cout);
  solver.solve(in, out);
  return 0;
}
