#pragma once
#include <stdio.h>
#include <sstream>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <utility>
#include <set>
#include <cctype>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <limits>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define bit(x,v) ((ll)x << v)

const ll INF = 1000000007;
const int MAX = 210000;
const int MOD = 1000000007;

long long fac[MAX], finv[MAX], inv[MAX];
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
		finv[i] = finv[i - 1] * inv[i] % MOD;
	}
}
ll gcd(ll a, ll b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
int pr[100010];
void uini(int n) {
	for (size_t i = 0; i <= n; i++)
	{
		pr[i] = i;
	}
}

int parent(int x) {
	if (x == pr[x]) return x;
	return pr[x] = parent(pr[x]);
}

bool unit(int x, int y) {
	int px = parent(x);
	int py = parent(y);

	if (px == py) return false;
	if (px < py) {
		pr[py] = px;
	}
	else {
		pr[px] = py;
	}
	return true;
}

// res[i][c] := i 文字目以降で最初に文字 c が登場する index (存在しないときは n)
vector<vector<int> > calcNext(const string& S) {
	int n = (int)S.size();
	vector<vector<int> > res(n + 1, vector<int>(26, n));
	for (int i = n - 1; i >= 0; --i) {
		for (int j = 0; j < 26; ++j) res[i][j] = res[i + 1][j];
		res[i][S[i] - 'a'] = i;
	}
	return res;
}
// mod 1000000007 の世界で a += b する関数
void add(long long& a, long long b) {
	a += b;
	if (a >= MOD) a -= MOD;
}
ll slide(vector<ll>& v, ll a, ll b) {
	ll azv = abs(v[0] - a);
	ll bzv = abs(v[0] - b);
	ll aov = abs(v[1] - a);
	ll bov = abs(v[1] - b);
	v[0] = a;
	v[1] = b;
	return max((azv + bov), (bzv + aov));
}


bool a[100010];
string gcs(string s, string t) {

	ll high = min(s.size(), t.size());
	ll low = 0;
	ll mid = -1;
	for (size_t i = 0; i < 20; i++)
	{
		mid = (high + low) / 2;
		string st = s.substr(0, mid);
		string tt = t.substr(0, mid);
		if (st == tt) {
			low = mid;
		}
		else high = mid;

		if (s.size() <= mid || t.size() <= mid) continue;
		st = s.substr(0, mid + 1);
		tt = t.substr(0, mid + 1);
		if (st == tt) {
			low = mid + 1;
			mid = mid + 1;
		}
	}
	return s.substr(0,mid);
}
struct solver {
	map<string, pair<int, int>> memo;
	pii calc(string s) {

		if (s == "" || s == "()") {
			return memo[s] = pii(0, 0);
		}
		else if (s == "((") return memo[s] = pii(1, 1);
		else if (s == "))") return memo[s] = pii(1, 0);

		auto res = rec(s);
		if (s.size() == 2) {
			res.first = 0;
			res.second = 0;
			if (s[0] == ')') {
				res.first = 1;
			}
			if (s[1] == '(') {
				res.first++;
				res.second = 1;
			}
		}

		return res;
	}
	pair<int, int> rec(string s) {

		if (memo.count(s)) return memo[s];
		pii res;
		res.first = INF;
		res.second = INF;
		int n = s.size();
		if(n == 0) return res = pii(0, 0);
		res = calc(s.substr(1, n - 2));
		if (res.first > 0) {
			res.second++;
		}

		if (s[0] == ')') {
			res.first++;
		}
		if (s[s.size() - 1] == '(') {
			res.first++;
			res.second = s.size() - 1;
		}
		for (int i = s.size() - 2; i > 1; i -= 2)
		{
			//if (s == "()()") {
			//	cout << endl;
			//}
			//if (s == "()()()") {
			//	cout << endl;
			//}
			string ls = s.substr(0, i);
			auto left = calc(ls);
			string rs = s.substr(i, n - i);
			auto right = calc(rs);

			int lval = left.first + right.first;
			int rval = left.second;
			if (right.first > 0)
				rval = i + right.second;
			if ((res.first + res.second) > (lval + rval))
			{
				res.first = lval;
				res.second = rval;
			}
		}

		return memo[s] = res;
	}

};

struct dist {
	ll cost;
	vector<int> vec;
	
};
dist d[105][105];
pair<int, int> edge[105][105];
bool use[105];

void solv() {
	
	int n,m;
	cin >> n >> m;
	for (size_t i = 0; i < 105; i++)
	{
		for (size_t j = 0; j < 105; j++)
		{
			if (i == j) {
				d[i][j].cost = 0;
			}
			else
				d[i][j].cost = INF;
		}
	}

	for (size_t i = 0; i < m; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		d[a][b].cost = c;
		d[a][b].vec.push_back(i);
		d[b][a].cost = c;
		d[b][a].vec.push_back(i);
	}



	for (size_t i = 1; i <= n; i++)
	{
		for (size_t f = 1; f <= n; f++)
		{
			for (size_t t = 1; t <= n; t++)
			{
				dist ds = d[f][t];
				if (ds.cost > (d[f][i].cost + d[i][t].cost)) {
					d[f][t].cost = d[f][i].cost + d[i][t].cost;

					d[f][t].vec.clear();
					d[f][t].vec.insert(d[f][t].vec.end(), d[f][i].vec.begin(),d[f][i].vec.end());
					d[f][t].vec.insert(d[f][t].vec.end(), d[i][t].vec.begin(), d[i][t].vec.end());
				}
			}
		}
	}

	int res = m;
	for (size_t i = 0; i < 105; i++)
	{
		for (size_t j = 0; j < 105; j++)
		{
			for (auto it : d[i][j].vec)
			{
				if (!use[it]) res--;
				use[it] = true;
			}
		}
	}
	cout << res << endl;
}

int main() {
	//COMinit();
	solv();

	return 0;
}


Measured memory_bytes: 2688