#include<iostream>
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<map>
#include<math.h>
#include<algorithm>
#include<iomanip>

using namespace std;

class Counting {
	unsigned long long p, n;
	vector<long long> invMemo, facMemo, facInvMemo;
public:
	Counting(unsigned long long nn, unsigned long long np) {
		p = np;
		n = nn;
		invMemo.resize(n + 1);
		facMemo.resize(n + 1);
		facInvMemo.resize(n + 1);
		facMemo[0] = 1;
		facMemo[1] = 1;
		facInvMemo[0] = 1;
		facInvMemo[1] = 1;
		invMemo[0] = 0;
		invMemo[1] = 1;
		for (unsigned long long i = 2; i <= n; i++) {
			invMemo[i] = p - (p / i)*invMemo[p%i] % p;
			facMemo[i] = (facMemo[i - 1] * i) % p;
			facInvMemo[i] = (facInvMemo[i - 1] * invMemo[i]) % p;
		}
	}
	unsigned long long fac(unsigned long long k) {
		return facMemo[k];
	}
	unsigned long long facInv(unsigned long long k) {
		return facInvMemo[k];
	}
	unsigned long long choose(unsigned long long n, unsigned long long k) {
		if (!(0 <= k && k <= n))
			return 0;
		return (((facMemo[n] * facInvMemo[k]) % p)*facMemo[n - k]) % p;
	}
	unsigned long long divide(unsigned long long a, unsigned long long b) {
		return (a * invMemo[b]) % p;
	}
	unsigned long long mod(unsigned long long a) {
		a %= p;
		if (a < 0) a += p;
		return a;
	}
	unsigned long long power(unsigned long long a, unsigned long long e) {
		unsigned long long ans = 1;
		for (; e > 0; e /= 2) {
			if (e % 2 != 0)
				ans = ans * a % p;
			a = a*a%p;
		}
		return ans;
	}
};

int sx, sy, tx, ty;
string ans;

string go(int x, int y, int x2, int y2) {
	string a;
	for (int i = 0; i < x2 - x; i++) {
		a += 'R';
	}
	for (int i = 0; i < y2 - y; i++)
		a += 'U';
	return a;
}

string back(int x, int y, int x2, int y2) {
	string a;
	for (int i = 0; i < -x2 + x; i++) {
		a += 'L';
	}
	for (int i = 0; i < -y2 + y; i++)
		a += 'D';
	return a;
}

class Edge {
public:
	int to, from, cost;
	bool used = false;
	Edge() {}
	int getTo(int x) {
		return x == to ? from : to;
	}
};

class Node {
public:
	int now, d;
	vector<int> edId;
	Node(){}
	bool operator>(Node &rnd) {
		return this->d > rnd.d;
	}
	bool operator<(Node &rnd) {
		return this->d < rnd.d;
	}
};

int n, m;
vector<int> a, b, c;
vector<Edge> ed;
vector<Node> prique;
vector<vector<int>> node;

int main() {
	cin >> n >> m;
	a.resize(m);
	b.resize(m);
	c.resize(m);
	for (int i = 0; i < m; i++)
		cin >> a[i] >> b[i] >> c[i];
	ed.resize(m);
	node.resize(n);
	for (int i = 0; i < m; i++) {
		ed[i].from = a[i] - 1;
		ed[i].to = b[i] - 1;
		ed[i].cost = c[i];
		node[a[i] - 1].push_back(i);
		node[b[i] - 1].push_back(i);
	}


	for (int i = 0; i < m; i++) {
		prique.clear();
		//if (ed[i].used)
		//	continue;
		vector<bool> t;
		t.resize(n);
		Node ans;
		Node N;
		t[ed[i].to] = true;
		N.now = ed[i].to;
		N.d = 0;
		prique.push_back(N);
		while (true)
		{
			sort(prique.begin(), prique.end());
			if (prique[0].now == ed[i].from) {
				for (int j = 0; j < prique[0].edId.size(); j++) {
					ed[prique[0].edId[j]].used = true;
				}
				break;
			}
			t[prique[0].now] = true;
			for (int j = 0; j < node[prique[0].now].size(); j++) {
				if (t[ed[node[prique[0].now][j]].getTo(prique[0].now)])
					continue;
				Node M;
				M.d = prique[0].d + ed[node[prique[0].now][j]].cost;
				M.now = ed[node[prique[0].now][j]].getTo(prique[0].now);
				M.edId.push_back(node[prique[0].now][j]);
				prique.push_back(M);
			}
			prique.erase(prique.begin());
		}
	}
	int ans = 0;
	for (int i = 0; i < ed.size(); i++)
		if (!ed[i].used)
			ans++;
	cout << ans << endl;
//	cin >> n;
	return 0;
}