#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define PI acos(-1)
#define vi vector<int>
#define pi pair<int, int>
#define pl pair<ll, ll>
template<class T> istream &operator>>(istream&is,vector<T>&v){for(auto &elemnt:v)is>>elemnt;return is;}
template<class T,class U> istream &operator>>(istream&is,pair<T,U>&p){is>>p.first>>p.second;return is;}
const int MOD = 1e9+ 7;
const int INF = numeric_limits<int>::max() - (int)1e8;
const ll INFLL = numeric_limits<ll>::max() - (ll)1e17;

template<typename T>
struct edge {
    pair<int, int> arrow;
    T cost;

    edge(int source, int to, T cost) : arrow(source, to), cost(cost) {}
    edge(int to, T cost) : arrow(-1, to), cost(cost) {}

    edge &operator=(const int &vertex) {
        arrow.second = vertex;
        return *this;
    }

    operator int() const { return arrow.second; }
};

template<typename T>
struct UnWeightedGraph : vector<vector<edge<T>>> {
    bool is_directed_graph;
    explicit UnWeightedGraph(size_t size, bool is_directed_graph) : vector<vector<edge<T>>>(size), is_directed_graph(is_directed_graph) {}

    void add_edge(int source, int to) {
        vector<vector<edge<T>>>::operator[](source).emplace_back(to, 0);
        if (!is_directed_graph) vector<vector<edge<T>>>::operator[](to).emplace_back(source, 0);
    }
};

template<typename T>
struct WeightedGraph : UnWeightedGraph<T> {
    explicit WeightedGraph(size_t size, bool is_directed_graph) : UnWeightedGraph<T>(size, is_directed_graph) {}

    void add_edge(int source, int to, T cost) {
        UnWeightedGraph<T>::operator[](source).emplace_back(to, cost);
        if (!UnWeightedGraph<T>::is_directed_graph) UnWeightedGraph<T>::operator[](to).emplace_back(source, cost);
    }
};

template<typename T>
class Dijkstra {
private:
    WeightedGraph<T> &graph;
    vector<vector<T>> shortest_distance;

    void exec_dijkstra(int start_vertex, const T MAX_INF) {
        shortest_distance[start_vertex] = vector<T>(graph.size(), MAX_INF);

        priority_queue<pair<int, T>, vector<pair<int, T>>, greater<>> next_edges;
        vector<T> &now_distance = shortest_distance[start_vertex];
        now_distance[start_vertex] = 0;
        next_edges.emplace(start_vertex, now_distance[start_vertex]);
        while (!next_edges.empty()) {
            int now_vertex;
            T now_cost;
            tie(now_vertex, now_cost) = next_edges.top();
            next_edges.pop();
            if (now_distance[now_vertex] < now_cost) continue;
            for (auto &next_vertex : graph[now_vertex]) {
                T next_cost = now_cost + next_vertex.cost;
                if (now_distance[next_vertex] <= next_cost) continue;
                now_distance[next_vertex] = next_cost;
                next_edges.emplace(next_vertex, next_cost);
            }
        }
    }

public:
    explicit Dijkstra(WeightedGraph<T> &graph) : graph(graph), shortest_distance(graph.size()) {}

    T query_overwrite(int start_vertex, int end_vertex, const T MAX_INF) {
        exec_dijkstra(start_vertex, MAX_INF);
        return shortest_distance[start_vertex][end_vertex];
    }
 
    T query(int start_vertex, int end_vertex, const T MAX_INF)  {
        if (shortest_distance[start_vertex].empty()) exec_dijkstra(start_vertex, MAX_INF);
        return shortest_distance[start_vertex][end_vertex];
    }

    void query(int start_vertex, const T MAX_INF) { if (shortest_distance[start_vertex].empty()) exec_dijkstra(start_vertex, MAX_INF); }

    // read only
    const vector<T> &operator[] (const int start_vertex) const { return shortest_distance[start_vertex]; }
};

int main() {
    int N, M;
    cin >> N >> M;
    WeightedGraph<int> G(N, false);
    for (int i = 0; i < M; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        a--;  b--;
        G.add_edge(a, b, c);
    }
    auto dist = Dijkstra<int>(G);
    set<int> ans;
    for (int i = 0; i < N; i++) {
        dist.query(i, INF);
        for (auto temp : dist[i]) {
            if (temp == 0) continue;
            ans.insert(temp);
        }
    }
    cout << M - ans.size() << endl;
} 