#include <bits/stdc++.h>
using namespace std;
 
/*てんぷれぞーん！*/
struct edge {int to,cost;};
typedef long long ll;
typedef pair<int,int> P;
typedef vector<int> VI;
typedef vector<edge> VE;
//static const int INF = 2147483647;
static const int INF = 1000000000;
static const long long llINF = 9223372000000000000;
static const int NIL = -1;
static const int MOD = 1000000007;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define np next_permutation
#define pq priority_queue
/* t y p o っ て 知 っ て る ゥ ！ ？ */
#define itn int
#define scnaf scanf
#define reutnr return
#define scamf scanf
//int dx4[4] = {0,1,0,-1}, dy4[4] = {-1,0,1,0};
//int dx5[5] = {-1,0,0,0,1}, dy5[5] = {0,-1,0,1,0};
//int dx8[8] = {-1,0,1,1,1,0,-1,-1}, dy8[8] = {1,1,1,0,-1,-1,-1,0};
//int dx9[9] = {-1,0,1,1,1,0,-1,-1,0}, dy9[9] = {1,1,1,0,-1,-1,-1,0,0};
//#define int ll
//#define INF llINF

const int NMAX = 120;
 
int n,m;    //nが頂点の数、mが辺の数
bool rinsetsu[NMAX][NMAX];    //最後に使うよ
int d[NMAX][NMAX];      //WF用テーブル
int prev[NMAX][NMAX];   //prev[i][j]はiからjへの最短路におけるjの手前の頂点

void WF(){
    for(int k=0;k<n;k++){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(d[i][j]>d[i][k]+d[k][j]){
                    d[i][j] = d[i][k] + d[k][j];
                    prev[i][j] = prev[k][j];
                }
            }
        }
    }
}

void delete_path(int start,int goal){
    VI path;
    int via=0,current;
    for(current=goal;current!=start;current=prev[start][current]){
        path.pb(current);
    }
    path.pb(start);

    for(int i=0;i<path.size()-1;i++){
        rinsetsu[path[i]][path[i+1]] = rinsetsu[path[i+1]][path[i]] = false;
    }
}

void debug(){
    printf("\n");
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++) printf("%d ",d[i][j]);
        printf("\n");
    }
    printf("\n");
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++) printf("%d ",prev[i][j]);
        printf("\n");
    }
    printf("\n");
}

void initializer(){
    memset(d,INF,sizeof(d));
    memset(rinsetsu,false,sizeof(rinsetsu));
    for(int i=0;i<NMAX;i++) d[i][i] = 0;
    for(int i=0;i<NMAX;i++){
        for(int j=0;j<NMAX;j++) prev[i][j] = i;
    }
}

signed main(){
    initializer();

    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int tmp1,tmp2,tmp3;
        scanf("%d%d%d",&tmp1,&tmp2,&tmp3);
        tmp1--; tmp2--;
        rinsetsu[tmp1][tmp2] = rinsetsu[tmp1][tmp2] = true;
        d[tmp1][tmp2] = d[tmp2][tmp1] = tmp3;
    }
    //debug();

    WF();

    //debug();

    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++) delete_path(i,j);
    }

    int ans = 0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(rinsetsu[i][j]) ans++;
        }
    }

    printf("%d\n",ans);
}