#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
const ll MOD = (ll)1e9 + 7;
const ll HINF = (ll)1e18;
const ll LINF = (ll)1e9;
class Dijkstra {
 public:
  vector<vector<pair<int, int>>> edge;
  vector<vector<int>> dist;
  void set(int node_) {
    edge.resize(node_);
    dist.resize(node_);
    for (int i = 0; i < int(node_); i++) dist[i].resize(node_);
    for (int i = 0; i < int(node_); i++)
      for (int j = 0; j < int(node_); j++) dist[i][j] = LINF;
  }
  void dijkstra(int start) {
    priority_queue<pair<int, int>, vector<pair<int, int>>,
                   greater<pair<int, int>>>
        pq;
    dist[start][start] = 0;
    pq.push({0, start});
    while (!pq.empty()) {
      int from = pq.top().second;
      pq.pop();
      for (int i = 0; i < int(edge[from].size()); i++) {
        int to = edge[from][i].first;
        if (dist[start][to] > dist[start][from] + edge[from][i].second) {
          dist[start][to] = dist[start][from] + edge[from][i].second;
          pq.push({dist[start][from] + edge[from][i].second, to});
        }
      }
    }
  }
};
class Ford_Fulkerson {
 public:
  struct edge {
    int to, cap, rev;
  };
  int node, start, goal;
  vector<vector<edge>> graph;
  vector<bool> visit;
  void set(int node_, int start_, int goal_) {
    node = node_;
    start = start_;
    goal = goal_;
    graph.resize(node);
    visit.resize(node);
  }
  void make_edge(int from, int to, int cap) {
    graph[from].push_back({to, cap, (int)graph[to].size()});
    graph[to].push_back({from, 0, (int)graph[from].size() - 1});
  }
  int dfs(int from, int flow) {
    if (from == goal) return flow;
    visit[from] = false;
    for (int i = 0; i < int(graph[from].size()); i++) {
      if (visit[graph[from][i].to] && (graph[from][i].cap > 0)) {
        int dflow = dfs(graph[from][i].to, min(flow, graph[from][i].cap));
        if (dflow > 0) {
          graph[from][i].cap -= dflow;
          graph[graph[from][i].to][graph[from][i].rev].cap += dflow;
          return dflow;
        }
      }
    }
    return 0;
  }
  int maxflow(void) {
    int maxflow = 0;
    while (1) {
      for (int i = 0; i < int(graph.size()); i++) visit[i] = true;
      int flow = dfs(start, 1);
      if (flow == 0) return maxflow;
      maxflow += flow;
    }
  }
};
class Least_Common_Ancestor {
 public:
  int node;
  int MAXLOG2;
  vector<vector<int>> edge;
  vector<int> depth;
  vector<vector<int>> parent;
  void set(int node_, int MAXLOG2_) {
    node = node_;
    MAXLOG2 = MAXLOG2_;
    edge.resize(node);
    depth.resize(node);
    parent.resize(node);
    for (int i = 0; i < int(node); i++) parent[i].resize(MAXLOG2);
  }
  void dfs(int root, int root_from) {
    depth[root] = 0;
    parent[root][0] = root_from;
    stack<pair<int, int>> st;
    st.push({root, root_from});
    while (!st.empty()) {
      int from = st.top().first;
      int from_from = st.top().second;
      st.pop();
      for (int i = 0; i < int(edge[from].size()); i++) {
        int to = edge[from][i];
        if (to != from_from) {
          depth[to] = depth[from] + 1;
          parent[to][0] = from;
          st.push({to, from});
        }
      }
    }
    return;
  }
  void initialize(int N) {
    for (int k = 0; k < int(MAXLOG2 - 1); k++) {
      for (int i = 0; i < int(N); i++) {
        if (parent[i][k] < 0)
          parent[i][k + 1] = -1;
        else
          parent[i][k + 1] = parent[parent[i][k]][k];
      }
    }
    return;
  }
  int get(int a, int b) {
    if (depth[a] > depth[b]) swap(a, b);
    for (int k = 0; k < int(MAXLOG2 - 1); k++)
      if (((depth[b] - depth[a]) >> k) & 1) b = parent[b][k];
    if (a == b) return a;
    for (int k = int(MAXLOG2 - 1); k >= 0; k--) {
      if (parent[a][k] != parent[b][k]) {
        a = parent[a][k];
        b = parent[b][k];
      }
    }
    return parent[a][0];
  }
};
void YN(bool flag) { cout << ((flag) ? "YES" : "NO") << endl; }
void Yn(bool flag) { cout << ((flag) ? "Yes" : "No") << endl; }
void yn(bool flag) { cout << ((flag) ? "yes" : "no") << endl; }
int main() {
  int N, M;
  cin >> N >> M;
  Dijkstra d;
  d.set(N);
  vector<int> a(M), b(M), c(M);
  for (int i = 0; i < int(M); i++) {
    cin >> a[i] >> b[i] >> c[i];
    a[i]--;
    b[i]--;
    c[i]--;
    d.edge[a[i]].push_back({b[i], c[i]});
    d.edge[b[i]].push_back({a[i], c[i]});
  }
  for (int i = 0; i < int(N); i++) d.dijkstra(i);
  int sum = 0;
  for (int k = 0; k < int(M); k++) {
    bool flag = true;
    for (int i = 0; i < int(N); i++) {
      for (int j = 0; j < int(N); j++) {
        if (d.dist[i][a[k]] == c[k] + d.dist[b[k]][j]) {
          flag = false;
          break;
        }
      }
    }
    if (flag) sum++;
  }
  cout << sum << endl;
  return 0;
}
