#include<bits/stdc++.h>

using namespace std;
typedef unsigned int uint;
typedef long long int ll;
typedef unsigned long long int ull;

#define debugv(v) printf("L%d %s => ",__LINE__,#v);for(auto e:v){cout<<e<<" ";}cout<<endl;
#define debugm(m) printf("L%d %s is..\n",__LINE__,#m);for(auto v:m){for(auto e:v){cout<<e<<" ";}cout<<endl;}
#define debuga(m,w) printf("L%d %s is => ",__LINE__,#m);for(int x=0;x<(w);x++){cout<<(m)[x]<<" ";}cout<<endl;
#define debugaa(m,w,h) printf("L%d %s is..\n",__LINE__,#m);for(int y=0;y<(h);y++){for(int x=0;x<(w);x++){cout<<(m)[x][y]<<" ";}cout<<endl;}
#define debugaar(m,w,h) printf("L%d %s is..\n",__LINE__,#m);for(int y=0;y<(h);y++){for(int x=0;x<(w);x++){cout<<(m)[y][x]<<" ";}cout<<endl;}
#define ALL(v) (v).begin(),(v).end()
#define BIGINT 0x7FFFFFFF
#define E107 1000000007ll
void printbit(int u){if(u==0)cout<<0;else{int s=0,k=0;for(;0<u;u>>=1,k++)s=(s<<1)|(u&1);for(;0<k--;s>>=1)cout<<(s&1);}}

#define TIME chrono::system_clock::now()
#define MILLISEC(t) (chrono::duration_cast<chrono::milliseconds>(t).count())

template<typename T1,typename T2>
ostream& operator <<(ostream &o,const pair<T1,T2> p){o<<"("<<p.first<<":"<<p.second<<")";return o;}


class Flow{
public:
    size_t n;
    struct Arrow{
        int from,to;
        int w_max;
        Arrow(int from=0,int to=0,int w=1):from(from),to(to),w_max(w){}
    };
    vector<vector<int>> vertex_to;
    vector<vector<int>> vertex_from;
    vector<Arrow> arrow;
    
    Flow(int n,int m=5010):n(n),vertex_to(n),vertex_from(n){arrow.reserve(m);}
    
    void connect(int from, int to, int w_max){
        vertex_to[from].push_back(arrow.size()); // toto
        vertex_from[to].push_back(arrow.size()); // fromfrom
        arrow.emplace_back(from,to,w_max);
    }
    size_t degree(int v){
        return vertex_to[v].size() + vertex_from[v].size();
    }
    size_t degree_in(int v){
        return vertex_from[v].size();
    }
    size_t degree_out(int v){
        return vertex_to[v].size();
    }
};

int width,height;
int m,n;


int main(){
    int i,j,k;
    int x,y,a,b;
    
    cin >> n >> m;
    
    Flow graph(n,m+10);
    set<pair<int,int>> check;
    
    for (i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&x);
        a--;b--;
        graph.connect(a,b,x);
    }
    
    vector<int> visited(n);
    vector<bool> visited2(n);
    for (int start=0;start<n;start++){
        
        fill(ALL(visited),0x7FFFFFFF);
        
        priority_queue<vector<int>> pq;
        
        pq.emplace(vector<int>{0,start});
        visited[start]=0;
        
        while(!pq.empty()){
            const vector<int> &p = pq.top();
            int dist = -p[0];
            int v = p[1]; 
            pq.pop();
            
            if (visited[v]<dist){
                continue;
            }
            
            for (int ia : graph.vertex_to[v]){
                Flow::Arrow& a = graph.arrow[ia];
                if (dist+a.w_max < visited[a.to]){
                    visited[a.to] = dist+a.w_max;
                    pq.emplace(vector<int>{-(dist+a.w_max),a.to,v});
                }
            }
            for (int ia : graph.vertex_from[v]){
                Flow::Arrow& a = graph.arrow[ia];
                if (dist+a.w_max < visited[a.from]){
                    visited[a.from] = dist+a.w_max;
                    pq.emplace(vector<int>{-(dist+a.w_max),a.from,v});
                }
            }
        }
        //debugv(visited);
        fill(ALL(visited2),false);
        
        pq.emplace(vector<int>{0,start});
        visited2[start]=true;
        while(!pq.empty()){
            const vector<int> &p = pq.top();
            //int dist = -p[0];
            int v = p[1]; 
            int dist = visited[v];
            pq.pop();
            
            for (int ia : graph.vertex_to[v]){
                Flow::Arrow& a = graph.arrow[ia];
                if (dist+a.w_max == visited[a.to] || dist-a.w_max == visited[a.to]){
                    //printf("%d op %d == %d (%d->%d)\n",dist,a.w_max,visited[a.to],v,a.to);
                    check.insert(make_pair(min(v,a.to),max(v,a.to)));
                }
                if (!visited2[a.to]){
                    visited2[a.to]=true;
                    pq.emplace(vector<int>{-(dist+a.w_max),a.to,v});
                }
            }
            for (int ia : graph.vertex_from[v]){
                Flow::Arrow& a = graph.arrow[ia];
                if (dist+a.w_max == visited[a.from] || dist-a.w_max == visited[a.from]){
                    check.insert(make_pair(min(v,a.from),max(v,a.from)));
                }
                if (!visited2[a.from]){
                    visited2[a.from]=true;
                    pq.emplace(vector<int>{-(dist+a.w_max),a.from,v});
                }
            }
        }
    }
    //debugv(check)
    cout << (m-(int)check.size()) << endl;

    return 0;
}

Measured memory_bytes: 256