#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>

using namespace std;

const long long int INF=1e9;

int main() {
    int N, M;
    cin >> N >> M;

    vector<vector<pair<int , pair<int, long long int> > > > InVnC(N, \
        vector<pair<int , pair<int, long long int> > >());

    for(int m=0; m<M; m++) {
        int a, b;
        long long int c;
        cin >> a >> b >> c;
        InVnC[a-1].push_back(make_pair(m, make_pair(b-1, c)));
        InVnC[b-1].push_back(make_pair(m, make_pair(a-1, c)));
    }

    
    vector<bool> used_e(M, false);
    
    for(int s=0; s<N-1; s++) {
        vector<int> next_v;
        vector<bool> is_in_next_v(N, false);
        vector<long long int> cost_from_s(N, INF);
        vector<pair<bool, vector<int> > > seen_v(N, \
            pair<bool, vector<int> >(make_pair(false, vector<int>())));

        next_v.push_back(s);
        is_in_next_v[s]=true;
        cost_from_s[s]=0;
        
        for(int g=s+1; g<N; g++) {
            if(seen_v[g].first) {
                // if g are already seen in previous process, 
                // don't need to repeat the same process
                // just update used es
                for(int svi=0; svi<seen_v[g].second.size(); svi++) {
                    used_e[seen_v[g].second[svi]]=true;
                }
            } else {

                // int counter=0; // for debugging
                // while(!seen_v[g].first && counter<4) {

                while(!seen_v[g].first) {
                    // // for debugging
                    // cout << counter << "th time:" << endl;
                    // for(int nvi=0; nvi<next_v.size(); nvi++) {
                    //     cout << next_v[nvi] << " ";
                    // }
                    // cout << endl;

                    // Find minimum cost from s in next vs
                    // and set curent v as the min cost v
                    long long int min_cost=INF;
                    int cur_v, cvi;
                    for(int nvi=0; nvi<next_v.size(); nvi++) {
                        // // for debugging
                        // cout << "the candidate :" << next_v[nvi] << endl;
                        if(min_cost>cost_from_s[next_v[nvi]]) {
                            min_cost = cost_from_s[next_v[nvi]];
                            cur_v = next_v[nvi];
                            cvi = nvi;
                        }
                    }
                    
                    // delete cur v in next vs
                    // if cur_v==g then the rest of the process can be skipped
                    seen_v[cur_v].first = true;
                    if(seen_v[g].first) break;
                    next_v.erase(next_v.begin()+cvi);
                    is_in_next_v[cur_v] = false;
                    
                    // // for debugging
                    // cout << "cur v is " << cur_v << endl;

                    
                    for(int ti=0; ti<InVnC[cur_v].size(); ti++) {
                        int target_v=InVnC[cur_v][ti].second.first;
                        long long int cost_cur_v2target=InVnC[cur_v][ti].second.second;
                        int route_id_cur2target=InVnC[cur_v][ti].first;

                        if(seen_v[target_v].first) {
                            continue;
                        } else {
                            // push back target_v into next v
                            if(is_in_next_v[target_v]) {
                                ;
                            } else {
                                is_in_next_v[target_v]=true;
                                next_v.push_back(target_v);
                            }

                            // in this process, the cost and the route of target v
                            // should be updated
                            if(cost_from_s[target_v]>cost_from_s[cur_v]+cost_cur_v2target) {
                                // cost update
                                cost_from_s[target_v] = cost_from_s[cur_v]+cost_cur_v2target;
                                // route update
                                seen_v[target_v].second = seen_v[cur_v].second;
                                seen_v[target_v].second.push_back(route_id_cur2target);
                            }
                        }
                    }
                    // // for debugging
                    // counter++;
                }
                
                // // for debugging
                // cout << "aaaaa" << endl;

                // update used es
                for(int svi=0; svi<seen_v[g].second.size(); svi++) {
                    used_e[seen_v[g].second[svi]]=true;
                }

                // // for debugging
                // cout << "bbbbb" << endl;
            }
        }
    }

    int ans=0;
    for(int m=0; m<M; m++) {
        if(used_e[m]) {
            ;
        } else {
            // // for debugging
            // cout << m << endl;
            ans++;
        }
    }
    
    cout << ans << endl;
    
    return 0;
    
}

Measured memory_bytes: 384