#include <bits/stdc++.h>
using namespace std;
template <class T>
using lim = numeric_limits<T>;
set<pair<int, int>> tracker;
int getSmall(int costs[], bool inQ[], int n) {
  int compare = lim<int>::max();
  int minIndex;
  for (int i = 0; i < n; i++) {
    if (!inQ[i] && costs[i] < compare) {
      compare = costs[i];
      minIndex = i;
    }
  }
  return minIndex;
}
vector<int> dijkstra(vector<vector<int>> graph, int start) {
  int n = graph.size();
  int costs[n];
  vector<int> parent(n, 0);
  bool inQ[n];
  for (int i = 0; i < n; i++) {
    costs[i] = lim<int>::max();
    inQ[i] = false;
  }
  costs[start] = 0;
  parent[start] = -1;
  for (int i = 0; i < n - 1; i++) {
    int smallest = getSmall(costs, inQ, n);
    inQ[smallest] = true;
    for (int j = 0; j < n; j++) {
      if (graph[smallest][j] && !inQ[j] && costs[j] > graph[smallest][j]) {
        costs[j] = graph[smallest][j];
        parent[j] = smallest;
      }
    }
  }
  return parent;
}
void addToSet(int a, vector<vector<int>> graph) {
  vector<int> parent = dijkstra(graph, a);
  int n = graph.size();
  for (int i = 0; i < n; i++) {
    if (parent[i] >= 0) {
      tracker.insert(make_pair(min(i, parent[i]), max(i, parent[i])));
    }
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  vector<vector<int>> aMat(n, vector<int>(n, 0));
  for (int i = 0; i < m; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    aMat[a - 1][b - 1] = c;
    aMat[b - 1][a - 1] = c;
  }
  for (int i = 0; i < n; i++) {
    addToSet(i, aMat);
  }
  int size = tracker.size();
  cout << m - size << endl;
}
