#include <bits/stdc++.h>
using namespace std;
struct Node {
  vector<int> to;
  vector<int> cost;
  vector<pair<int, int> > detail;
  bool done = false;
  int minCost = INT_MAX;
  int from_node;
};
map<pair<int, int>, bool> used;
void shortest_route();
int djikstra(vector<Node> v, int start, int goal) {
  int next_from_index = -1;
  int nodeNum = int(v.size());
  v[start].minCost = 0;
  int now = start;
  while (true) {
    v[now].done = true;
    v[now].from_node = next_from_index;
    if (now == goal) {
      int i = now;
      while (true) {
        if (v[i].from_node == -1) break;
        if (now != i) {
          used[{i, v[i].from_node}] = true;
          used[{v[i].from_node, i}] = true;
        }
        i = v[i].from_node;
      }
      return v[now].minCost;
    }
    int edgeNum = int(v[now].to.size());
    for (int i = 0; i < edgeNum; i++) {
      int nextNodeIndex = v[now].to[i];
      v[nextNodeIndex].minCost =
          min(v[nextNodeIndex].minCost, v[now].minCost + v[now].cost[i]);
    }
    int minNodeIndex = -1;
    int minNodeCost = INT_MAX;
    for (int i = 0; i < nodeNum; i++) {
      if (i == now) continue;
      if (minNodeCost > v[i].minCost && !v[i].done) {
        minNodeIndex = i;
        minNodeCost = v[i].minCost;
      }
    }
    next_from_index = now;
    now = minNodeIndex;
  }
}
int res = 0;
int main() {
  int node_num, edge_num;
  cin >> node_num >> edge_num;
  vector<Node> v(node_num);
  for (int i = 0; i < edge_num; i++) {
    int to, from, cost;
    cin >> from >> to >> cost;
    to--;
    from--;
    v[from].to.push_back(to);
    v[from].cost.push_back(cost);
    v[to].to.push_back(from);
    v[to].cost.push_back(cost);
  }
  for (int i = 0; i < node_num; i++) {
    for (int j = 0; j < node_num; j++) {
      if (i == j) continue;
      djikstra(v, i, j);
    }
  }
  cout << edge_num - int(used.size()) / 2 << endl;
}
