// #include <bits/stdc++.h>
// using namespace std;
// #define rep(i,n) for (int (i)=(0);(i)<(int)(n);++(i))
//
// int N, M;
// bool used_cost[101][101];
// int d[101][101];
// bool used[101];
// int pv[101];
//
// const int INF=1e9+7;
//
// bool ans[101];
//
// // void dijkstra(int s) {
// //     fill(d, d+N, INF);
// //     fill(used, used+N, false);
// //     fill(pv, pv+N, -1);
// //     d[s]=0;
// //
// //     while (true) {
// //         int v=-1;
// //         rep(u,N) {
// //             if (!used[u] && (v==-1 || d[u] < d[v])) v=u;
// //         }
// //         if (v==-1) break;
// //         used[v]=true;
// //
// //         rep(u,N) {
// //             if (d[u]>d[v]+cost[v][u]) {
// //                 d[u]=d[v]+cost[v][u];
// //                 pv[u]=v;
// //             }
// //         }
// //     }
// // }
//
// void warshall_floyd() {
//     fill(pv, pv+N, -1);
//     rep(k,N) rep(i,N) rep(j,N) {
//         if (d[i][j] < d[i][k]+d[k][j]) {
//             pv[j]=i;
//         }
//         else {
//             pv[k]=i;
//             pv[]
//         }
//     }
// }
//
// void get_path(int t) {
//     int a=-1,b=t;
//     for (;t!=-1; t=pv[t]) {
//         b=t;
//         if (a != -1 && b != -1) {
//             used_cost[a][b]=true;
//             used_cost[b][a]=true;
//         }
//         a=b;
//     }
// }
//
// int main() {
//     cin>>N>>M;
//     fill(ans, ans+N, false);
//     vector<pair<int,int>> m(M);
//     rep(i,N) rep(j,N) {
//         if (i==j) d[i][j]=0;
//         else d[i][j]=INF;
//     }
//     rep(i,M) {
//         int a,b,c;cin>>a>>b>>c;
//         a--; b--;
//         m[i]={a,b};
//         d[a][b]=c;
//         d[b][c]=c;
//     }
//     rep(i,N) {
//         dijkstra(i);
//         rep(j,N) {
//             if (i!=j) get_path(j);
//         }
//     }
//
//     int c=0;
//     rep(i,M) {
//         if (!used_cost[m[i].first][m[i].second] && !used_cost[m[i].second][m[i].first]) c++;
//     }
//
//     cout<<c<<endl;
//
//     return 0;
// }

#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int (i)=(0);(i)<(int)(n);++(i))

int N, M;
int cost[101][101];
bool used_cost[101][101];
int d[101];
bool used[101];
int pv[101];

const int INF=1e9+7;

bool ans[101];

void dijkstra(int s) {
    fill(d, d+N, INF);
    fill(used, used+N, false);
    fill(pv, pv+N, -1);
    d[s]=0;

    while (true) {
        int v=-1;
        rep(u,N) {
            if (!used[u] && (v==-1 || d[u] < d[v])) v=u;
        }
        if (v==-1) break;
        used[v]=true;

        rep(u,N) {
            if (d[u]>d[v]+cost[v][u]) {
                d[u]=d[v]+cost[v][u];
                pv[u]=v;
            }
        }
    }
}

void get_path(int t) {
    int a=-1,b=t;
    for (;t!=-1; t=pv[t]) {
        b=t;
        if (a != -1 && b != -1) {
            used_cost[a][b]=true;
            used_cost[b][a]=true;
        }
        a=b;
    }
}

int main() {
    cin>>N>>M;
    fill(ans, ans+N, false);
    vector<pair<int,int>> m(M);
    rep(i,N) rep(j,N) cost[i][j]=INF;
    rep(i,M) {
        int a,b,c;cin>>a>>b>>c;
        a--; b--;
        m[i]={a,b};
        cost[a][b]=c;
        cost[b][a]=c;
    }
    rep(i,N) {
        dijkstra(i);
        rep(j,N) {
            if (i!=j) get_path(j);
        }
    }

    int c=0;
    rep(i,M) {
        if (!used_cost[m[i].first][m[i].second] && !used_cost[m[i].second][m[i].first]) c++;
    }

    cout<<c<<endl;

    return 0;
}


Measured memory_bytes: 256