-- heap
local Heap = {}
function Heap.new(upper_func)
    local self = setmetatable({}, {__index = Heap})
    self.a = {}
    self.upper_func = upper_func
    self.upper = function(k1, k2)
        assert(k1 < k2)
        if k1 == 0 then
            return false
        else
            return upper_func(self.a[k1], self.a[k2])
        end
    end
    self.lower = function(k1, k2)
        return not self.upper(k1, k2)
    end
    return self
end

function Heap:count()
    return #self.a
end

function Heap:_swap(k1, k2)
    local old_k1 = self.a[k1]
    self.a[k1] = self.a[k2]
    self.a[k2] = old_k1
end

function Heap:upheap(newk)
    local ku = newk // 2
    local k = newk
    while ku > 0 and self.lower(ku, k) do
        self:_swap(ku, k)
        k = k//2
        ku = ku//2
    end
end

function Heap:insertq(e)
    table.insert(self.a, e)
    self:upheap(#self.a)
end

function Heap:downheap(newk)
    local k = newk
    while k <= #self.a//2 do
        local kdl = k*2
        local kdr = kdl + 1
        local kd
        if kdr <= #self.a and self.lower(kdl, kdr) then
            kd = kdr
        else
            kd = kdl
        end
        if self.upper(k, kd) then
            break
        end
        self:_swap(k, kd)
        k = kd
    end
end

function Heap:top()
    assert(#self.a >= 1)
    return self.a[1]
end

function Heap:remove_top()
    assert(#self.a >= 1)
    local v = self.a[1]
    self:_swap(1, #self.a)
    table.remove(self.a)
    self:downheap(1)
    return v
end

function Heap:replace_top(e)
    assert(#self.a >= 1)
    local old_v = self.a[1]
    local swapped = false
    if self.upper_func(old_v, e) then
        self.a[1] = e
        self:downheap(1)
        swapped = true
    end
    return swapped, old_v
end

-- dijkstra's algorithm
local function find_shortest_path_all(adj_list, src)
    local from1 = {}
    from1[src] = 0
    local prevs = {}
    local q = Heap.new(function (v1, v2)
        return v1[2] < v2[2]
    end)
    local proved = {}
    q:insertq({src, 0, {}})
    while q:count() > 0 do
        local elem = q:remove_top()
        local cur_v, cur_cost, path = table.unpack(elem)
        if not proved[cur_v] then
            proved[cur_v] = true
            --[[
            if cur_v == dst then
                return cur_cost
            end
            ]]
            path = {table.unpack(path), cur_v}
            for _, link in ipairs(adj_list[cur_v]) do
                local to, cost = table.unpack(link)
                if not proved[to] then
                    -- compare costs
                    local before = from1[to]
                    local candidate = cur_cost + cost
                    if not before or candidate < before then
                        from1[to] = candidate
                        prevs[to] = cur_v
                        q:insertq({to, candidate, path})
                    end
                end
            end
        end
    end
    return from1, prevs
end

local function make_path(prevs, src, dst)
    local path = {}
    path[#path+1] = dst
    local cur = dst
    while cur ~= src do
        local next = prevs[cur]
        path[#path+1] = next
        cur = next
    end
    -- reverse
    for i=1, #path//2 do
        path[i], path[#path-i+1] = path[#path-i+1], path[i]
    end
    return path
end

-- main
local N, M = io.read("n", "n")

local edges = {}
for i=1,M do
    local a, b, cost = io.read("n", "n", "n")
    edges[#edges+1] = {a, b, cost}
end

local adj_list = {}
for i=1,N do
    adj_list[i] = {}
end

local edge_check = {}
for s=1,N do
    edge_check[s] = {}
end

for i=1,M do
    local a, b, cost = table.unpack(edges[i])
    local list = adj_list[a]
    list[#list+1] = {b, cost}
    local list2 = adj_list[b]
    list2[#list2+1] = {a, cost}
    local small = math.min(a, b)
    local big = math.max(a, b)
    edge_check[small][big] = 0
end


for s=1,N do
    local c, prevs = find_shortest_path_all(adj_list, s)
    for dd=1,N do
        if dd ~= s then
            local ss = prevs[dd]
            local small = math.min(ss, dd)
            local big = math.max(ss, dd)
            edge_check[small][big] = edge_check[small][big] + 1
        end
    end
end

local ans = 0
for s=1,N do
    for d=s+1,N do
        local count = edge_check[s][d]
        if count then
            --print(s,d,count)
            if count == 0 then
                ans = ans + 1
            end
        end
    end
end
print(ans)


Measured memory_bytes: 2168