#include <bits/stdc++.h>

#define FOR(i,n) for(int i=0;i<(n);++i)
#define FORU(i,j,k) for(int i=(j);i<=(k);++i)
#define FORD(i,j,k) for(int i=(j);i>=(k);--i)

#define error(args...) { vector<string> _v = split(#args, ','); err(_v.begin(), args); }

using namespace std;

using lli = long long int;
using pll = pair<lli, lli>;

string TYPE(int*)  { return "%d";   }
string TYPE(lli*)  { return "%lld"; }
string TYPE(char*) { return "%c";   }

void RD() {}
template<typename T, typename... Args> 
void RD(T* v, Args... args)
{
    scanf((" " + TYPE(v)).c_str(), v);
    RD(args...);
}

void PR(bool nl = true)
{ if(nl) printf("\n"); }
template<typename T, typename... Args> 
void PR(bool nl, T v, Args... args)
{
    printf((TYPE(&v) + " ").c_str(), v);
    PR(nl, args...);
}
template<typename... Args> 
void PR(Args... args)
{ PR(true, args...); }

vector<string> split(const string& s, char c)
{
    vector<string> v;
    stringstream ss(s);
    string x;
    while (getline(ss, x, c))
        v.emplace_back(x);
    return move(v);
}

void err(vector<string>::iterator) {}
template<typename T, typename... Args>
void err(vector<string>::iterator it, T a, Args... args)
{
    cerr << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << '\n';
    err(++it, args...);
}

const long long int oo = 1000*1000*1000;

struct Coord
{
    int x, y;
    Coord(int x = 0, int y = 0) : x(x), y(y) {}
    Coord operator + (const Coord& droite) const
    {
        return Coord(x + droite.x, y + droite.y);
    }
};

struct AB
{
    int k;
    vector<lli> arbre;
    AB(int _k = 20, lli def = 0)
    {
        k = _k;
        FOR(i, 1 << k)
            arbre.push_back(i < (1 << (k-1)) ? 0LL : def);
        FORD(i, ((1 << (k-1)) - 1), 1)
            arbre[i] = arbre[i << 1] + arbre[(i << 1) ^ 1];
    }
    void set(int i, lli x)
    {
        int feuille = i + (1 << (k-1));
        arbre[feuille] = x;
        iset(feuille >> 1);
    }
    void iset(int noeud)
    {
        if(noeud)
        {
            arbre[noeud] = arbre[noeud << 1] + arbre[(noeud << 1)  ^ 1];
            iset(noeud >> 1);
        }
    }
    lli sum(int deb, int fin, int noeud = 1, int p = 0, int q = -1)
    {
        if(q < p)
            q = 1 << (k-1);
        if(deb <= p && q <= fin)
            return arbre[noeud];
        if(deb >= q || fin <= p)
            return 0LL;
        int mil = (p + q) / 2;
        return sum(deb, fin, noeud << 1, p, mil) + sum(deb, fin, (noeud << 1) ^ 1, mil, q);
    }
};

struct Arc
{
	int a, b, c;
	bool use;
	Arc(int a = 0, int b = 0, int c = 0, bool use = false) : a(a), b(b), c(c), use(use) {}
	int other(int x)
	{
		return a ^ b ^ x;
	}
};

struct Pos
{
	int n;
	int dist;
	Pos(int n = 0, int dist = 0) : n(n), dist(dist) {}
	bool operator < (const Pos& droite) const
	{
		if(dist != droite.dist)
			return droite.dist < dist;
		return n > droite.n;
	}
};

Arc arcs[100*100+42];
vector<int> graph[142];
int dejaVu[142];

int main()
{
	int n, m;
	RD(&n, &m);
	FOR(i, m)
	{
		int a, b, c;
		RD(&a, &b, &c);
		--a; --b;
		arcs[i] = {a, b, c};
		graph[a].push_back(i);
		graph[b].push_back(i);
	}
	FOR(i, n)
	{
		FOR(j, n)
			dejaVu[j] = -1;
		priority_queue<Pos> file;
		file.push(Pos(i));
		while(file.size())
		{
			Pos cur = file.top();
			file.pop();
			if(dejaVu[cur.n] == -1)
			{
				dejaVu[cur.n] = cur.dist;
				for(auto a : graph[cur.n])
					file.push({arcs[a].other(cur.n), cur.dist + arcs[a].c});
			}
		}
		FOR(j, m)
			arcs[j].use |= (dejaVu[arcs[j].a] - dejaVu[arcs[j].b]) == arcs[j].c;
	}
	int count = 0;
	FOR(i, m)
		count += !arcs[i].use;
	PR(count);
    return 0;
}


Measured memory_bytes: 512