/*
これを入れて実行
g++ code.cpp
./a.out
 */
 
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <cstring>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <unordered_map>
#include <cmath>
#include <math.h>
#include <tuple>
#include <iomanip>
#include <bitset>
#include <functional>
#include <cassert>

#define all(x) (x).begin(),(x).end()
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
 
using namespace std;
typedef long long ll;
typedef long double ld;
 
int dy4[4] = {-1, 0, +1, 0};
int dx4[4] = {0, +1, 0, -1};
int dy8[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dx8[8] = {0, 1, 1, 1, 0, -1, -1, -1};
 
const long long INF = 1LL << 62;
const ll MOD = 1e9 + 7;
 
bool greaterSecond(const pair<int, int>& f, const pair<int, int>& s){
    return f.second > s.second;
}
 
ll gcd(ll a, ll b){
	if (b == 0)return a;
	return gcd(b, a % b);
}
 
ll lcm(ll a, ll b){
    return a / gcd(a, b) * b;
}

ll conbinationMemo[100][100];

void cmemoInit(){
    rep(i, 100){
        rep(j, 100){
            conbinationMemo[i][j] = -1;
        }
    }
}
 
ll nCr(ll n, ll r){
    if(conbinationMemo[n][r] != -1) return conbinationMemo[n][r];
    if(r == 0 || r == n){
        return 1;
    } else if(r == 1){
        return n;
    }
    return conbinationMemo[n][r] = (nCr(n - 1, r) + nCr(n - 1, r - 1));
}
 
ll nPr(ll n, ll r){
    r = n - r;
    ll ret = 1;
    for (ll i = n; i >= r + 1; i--) ret *= i;
    return ret;
}
//-----------------------ここから-----------
struct Edge{
    ll from;
    ll to;
    ll cost;
};
vector<ll> dijkstra(int start, int n, vector<vector<Edge>> &g, vector<ll> &prev){
    vector<ll> dist(n, INF);
    priority_queue<pair<ll,ll>, vector<pair<ll,ll>>, greater<pair<ll,ll>>> q;
    q.push(make_pair(0, start));
    dist[start] = 0;
    while(!q.empty()){
        ll now = q.top().second;
        ll nowdist = q.top().first;
        q.pop();
        if(dist[now] < nowdist) continue;
        for(int i = 0; i < g[now].size(); i++){
            ll next = g[now][i].to;
            ll nextcost = g[now][i].cost;
            if(dist[next] <= nowdist + nextcost) continue;
            dist[next] = nowdist + nextcost;
            prev[next] = now;
            q.push(make_pair(dist[next], next));
        }
    }
 
    return dist;
   
}
int main(void){
    ll n, m;
    cin >> n >> m;
    vector<vector<Edge>> g(n);
    map<pair<ll,ll>, int> mp;
    rep(i, m){
        ll a, b, c;
        cin >> a >> b >> c;
        Edge tmp;
        tmp.cost = c;
        a--, b--;
        tmp.to = b;
        tmp.from = a;
        g[a].push_back(tmp);
        swap(tmp.to, tmp.from);
        g[b].push_back(tmp);
        mp[{a, b}] = i;
        mp[{b, a}] = i;
    }

    vector<int> used(m, 0);
    rep(i, n){
        vector<ll> prev(n, -1);
        vector<ll> dist = dijkstra(i, n, g, prev);
        rep(j, n){
            if(i == j) continue;
            ll now = j;
            while(now != i){
                if(prev[now] == -1) break;
                used[mp[{now, prev[now]}]] = 1;
                now = prev[now];
            }
        }
    }

    ll ans = 0;
    rep(i, m){
        if(!used[i]) ans++;
    }
    cout << ans << endl;
}


Measured memory_bytes: 3788