// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC optimize("no-stack-protector")
// #pragma GCC optimize("fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,abm,mmx,popcnt,avx,avx2,tune=native")

#include <bits/stdc++.h>

using namespace std;

typedef int64_t ll;
typedef uint64_t ull;

const ll LINF = 9187201950435737471;
const ll nLINF = -9187201950435737472;
const ll INF = 2139062143;
const int nINF = -2139062144;
const ull ULINF = numeric_limits<ull>::max();
const ll MAXN = 100 + 15;
const ll MAXE = 1000 + 15;
const double PI = acos(-1);
const ll MOD = 998244353;
const double EPS = 1e-8;
auto seed = chrono::high_resolution_clock::now().time_since_epoch().count();
mt19937 rnd(seed);

bool isEqual(double a, double b) {
    return abs(a - b) <= EPS;
}

#define all(_v) _v.begin(), _v.end()
#define rall(v) v.rbegin(), v.rend()
#define sz(v) (int)(v.size())
#define sqr(_v) ((_v) * (_v))
#define vpi vector<pair<int, int>>
#define eb emplace_back
#define pb push_back
#define mod(x, m) ((x) % m + ((x) < 0  && ((x % m) != 0) ? m : 0))
#define vi vector<int>
#define pi pair<int, int>
#define minq(x, y) (x) = min(x, y)
#define maxq(x, y) (x) = max(x, y)


inline void IO() {
#if(DEBUG_LEVEL > 0)
    freopen("../input.txt", "r", stdin);
    freopen("../out.txt", "w", stdout);
#else
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
#endif
}

template <typename T>
istream& operator >> (istream& in, vector<T>& a) {
    for (auto& i : a)
        in >> i;
    return in;
}

template <typename T>
ostream& operator << (ostream& out, const vector<T>& a) {
    for (auto& i : a) {
        out << i << " ";
    }
    return out;
}

template <typename T, typename D>
istream& operator >> (istream& in, pair<T, D>& a) {
    in >> a.first >> a.second;
    return in;
}

template <typename T, typename D>
ostream& operator << (ostream& out, const pair<T, D>& a) {
    out << a.first << " " << a.second;
    return out;
}

//#define int ll

int cost[MAXE];
bool is_on_path[MAXE];
vpi adj[MAXN];
int dist[MAXN];

inline void solve() {
    int n, m;
    cin >> n >> m;
    vpi edges;
    for (int i = 0; i < m; ++i) {
        int a, b, c;
        cin >> a >> b >> c;
        edges.eb(a, b);
        cost[i] = c;
        adj[a].eb(b, i);
        adj[b].eb(a, i);
    }
    for (int i = 1; i <= n; ++i) {
        memset(dist, 127, sizeof(dist));
        dist[i] = 0;
        set <pi> q;
        q.insert({0, i});
        while (!q.empty()) {
            int v = q.begin()->second;
            q.erase(q.begin());
            for (auto [to, num] : adj[v]) {
                int nxt = dist[v] + cost[num];
                if (dist[to] > nxt) {
                    q.erase({dist[to], to});
                    dist[to] = nxt;
                    q.insert({nxt, to});
                }
            }
        }
        for (int i = 0; i < m; ++i) {
            auto [x, y] = edges[i];
            if (dist[x] == dist[y] + cost[i] || dist[y] == dist[x] + cost[i]) {
                is_on_path[i] = 1;
            }
        }
    }
    int ans = 0;
    for (int i = 0; i < m; ++i) {
        if (!is_on_path[i]) {
            ans++;
        }
    }
    cout << ans;
}

signed main() {
    IO();
    int t = 1;
//    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}






Measured memory_bytes: 3664