#include <bits/stdc++.h>
using namespace std;
const int INF = 100100100;
const int MAX_V = 1100;
int cost[MAX_V][MAX_V];
int d[MAX_V];
bool used[MAX_V];
int V;
int previ[MAX_V];
void dijkstra(int s) {
  fill(d, d + V, INF);
  fill(used, used + V, false);
  fill(previ, previ + V, -1);
  d[s] = 0;
  while (true) {
    int v = -1;
    for (int u = 0; u < (V); ++u) {
      if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
    }
    if (v == -1) break;
    used[v] = true;
    for (int u = 0; u < V; u++) {
      if (d[u] > d[v] + cost[v][u]) {
        d[u] = d[v] + cost[v][u];
        previ[u] = v;
      }
    }
  }
}
vector<int> get_path(int t) {
  vector<int> path;
  for (; t != -1; t = previ[t]) path.push_back(t);
  reverse(path.begin(), path.end());
  return path;
}
int main() {
  cin >> V;
  for (int i = 0; i < (V); ++i) {
    for (int j = 0; j < (V); ++j) {
      if (i == j) {
        cost[i][j] = 0;
      } else {
        cost[i][j] = INF;
      }
    }
  }
  int E;
  for (int i = 0; i < (E); ++i) {
    int from, to, c;
    cin >> from >> to >> c;
    from--;
    to--;
    cost[from][to] = c;
    cost[to][from] = c;
  }
  int flag[V][V];
  for (int i = 0; i < (V); ++i) {
    for (int j = 0; j < (V); ++j) {
      flag[i][j] = 0;
    }
  }
  for (int i = 0; i < (V); ++i) {
    dijkstra(i);
    for (int j = 0; j < (V); ++j) {
      vector<int> v = get_path(j);
      int from = i;
      for (int k = 0; k < (v.size()); ++k) {
        flag[from][v[k]] = 1;
        from = v[k];
      }
    }
  }
  int ans = 0;
  for (int i = 0; i < (V); ++i) {
    for (int j = 0; j < (V); ++j) {
      if (i != j && cost[i][j] != INF) {
        if (flag[i][j] == 0) ans++;
      }
    }
  }
  cout << ans / 2 << endl;
  return 0;
}
