#!/usr/bin/env fsharpi

open System;

let ParseIntN ( str : string ) =
    str.Split(' ')
    |> Array.map System.Int32.Parse

let ParseInt1 ( str : string ) =
    ParseIntN str |> fun arr -> arr.[0]

let ParseInt2 ( str : string ) =
    ParseIntN str |> fun arr -> (arr.[0],arr.[1])

let ParseInt3 ( str : string ) =
    ParseIntN str |> fun arr -> (arr.[0],arr.[1],arr.[2])

let ReadLinesN ( n : int ) =
    fun _ -> Console.ReadLine()
    |> Seq.initInfinite
    |> Seq.take n

let ReadLines =
    fun _ -> Console.ReadLine()
    |> Seq.initInfinite
    |> Seq.takeWhile ((<>) null)

type cost = int
type vertex = int
type edge = vertex * vertex * cost
type graph = System.Collections.Generic.Dictionary<vertex, cost> array

let DGraph (n : int) (edges : edge list) : graph =
    let g : graph = Array.init n (fun _ -> new System.Collections.Generic.Dictionary< vertex, cost>())
    List.iter (fun (f,t,c) -> g.[f].[t] <- c) edges
    g

let Graph (n : int) (edges : edge list) : graph =
    let redges = List.map (fun (f,t,c) -> (t,f,c)) edges
    DGraph n <| List.append edges redges

let Nodes (g: graph) : int =
    Array.length g

let Edges (g: graph) : edge list =
    seq { for i = 0 to ( Nodes g ) - 1 do yield (i,Seq.zip g.[i].Keys g.[i].Values) } 
    |> Seq.map (fun (f,ts) -> Seq.map (fun (t,c) -> ( f,t,c ) ) ts )
    |> Seq.fold Seq.append Seq.empty
    |> Seq.toList

let Transpose (g : graph) : graph =
    g
    |> Edges 
    |> List.map (fun (f,t,c) -> (t,f,c)) 
    |> DGraph (Nodes g) 

let Dump (g : graph) : unit =
    for i = 0 to (Nodes g) - 1 do
        let v = Seq.zip g.[i].Keys g.[i].Values
        printfn "%d :%A" i v
    done

let Path (g : graph) (src : vertex) (dst : vertex) : vertex list option =
    let nodes = Nodes g
    let visited = Array.create nodes -1
    let queue = new System.Collections.Generic.Queue< vertex * vertex >()
    queue.Enqueue (src, src)
    while( queue.Count <> 0 ) do
        let (f,t) = queue.Dequeue()
        if visited.[t] = -1 then
            visited.[t] <- f
            g.[t].Keys |> Seq.iter ( fun tt -> queue.Enqueue (t,tt) )
    done

    let mutable result = [dst]
    while ( List.head result <> src ) && ( List.head result <> -1 ) do
        let c = List.head result
        result <- visited.[ c ] :: result
    done
    if (List.head result <> -1) then Some result else None

type 'a _heap =
    | Empty
    | Node of int * 'a * 'a _heap * 'a _heap

let rec _merge (comp : 'a -> 'a -> int) (h1 : 'a _heap) (h2 : 'a _heap) =
    let Height = function
        | Empty -> 0
        | Node(h, _, _, _) -> h
    let MakeTree x a b =
        let ha = Height a 
        let hb = Height b
        if ha >= hb then Node(hb + 1, x, a, b) else Node(ha + 1, x, b, a)
    match h1,h2 with
    | x, Empty -> x
    | Empty, x -> x
    | (Node(_, x, l1, r1) as n1), (Node(_, y, l2, r2) as n2) when comp x y <= 0 -> MakeTree x l1 (_merge comp r1 n2)
    | (Node(_, x, l1, r1) as n1), (Node(_, y, l2, r2) as n2) when comp x y > 0 -> MakeTree y l2 (_merge comp n1 r2)
    | _,_ -> failwith "empty"

let _head (h : 'a _heap) =
    match h with
    | Empty -> failwith "empty"
    | Node(h, x, l, r) -> x

let _tail (comp : 'a -> 'a -> int) (h : 'a _heap) =
    match h with
    | Empty -> failwith "empty"
    | Node(_, _, l, r) -> _merge comp l r

type 'a pqueue = ('a -> 'a -> int)  * 'a _heap
let PriorityQueue (comp : 'a -> 'a -> int)  =
    ( comp , Empty )

let IsEmpty (q : 'a pqueue) : bool =
    q |> function | ( _ , h )  -> h = Empty

let Top (q : 'a pqueue) =
    q |> function | ( _ , h )  -> _head h

let Push (q : 'a pqueue) (v : 'a) =
    q |> function | ( c , h )  -> Node(1,v,Empty,Empty) |> _merge c h |> fun h' -> ( c, h' )

let Pop (q : 'a pqueue) =
    q |> function | ( c , h )  -> (_head h, ( c, _tail c h) )

let rec toSeq (q : 'a pqueue) =
    q |> Pop |> fun (h,t) -> seq{ yield h; yield! toSeq t }


let Dijkstra (g : graph) (root : vertex) : (graph * cost array) =
    let nodes = Nodes g
    let costs = Array.create nodes System.Int32.MaxValue
    costs.[root] <- 0

    let comp (_,a) (_,b) = 
        match a,b with
        | _ when a < b -> -1
        | _ when a > b ->  1
        | _ -> 0
    let pqueue = Seq.zip g.[root].Keys g.[root].Values
                 |> Seq.map (fun (t,c) -> (root,t,c))
                 |> Seq.fold ( fun q (f,t,c) -> Push q ((f,t,c), c) ) (PriorityQueue comp)

    let rec doit (costs : cost array) (edges : edge list) (pqueue : (edge * cost) pqueue) : cost array * edge list =
        if IsEmpty pqueue then
            costs, edges
        else
            let (((_,t,c) as e,ac),pqueue') = Pop pqueue
            if ac < costs.[t] then
                let edges' = e :: edges
                costs.[t] <- ac
                Seq.zip g.[t].Keys g.[t].Values
                |> Seq.map (fun (t',c') -> (t,t',c'))
                |> Seq.fold ( fun q (f,t,c) -> Push q ((f,t,c), ac + c) ) pqueue'
                |> doit costs edges'
            else
                doit costs edges pqueue'
    let (rc,re ) = doit costs [] pqueue
    DGraph nodes re, rc

let (n,m) = ParseInt2 <| Console.ReadLine()
let g = ReadLinesN m |> Seq.map ParseInt3 |> Seq.map (fun (f,t,ci) -> (f-1,t-1,ci)) |> Seq.toList |> Graph n

let g_e = new System.Collections.Generic.HashSet<vertex * vertex >()
//Edges g |> List.iter (fun (a,b,_) -> ignore(g_e.Add((min a b, max a b))))
Edges g |> List.iter (fun (a,b,_) -> ignore(g_e.Add((a,b))))

let p_e = new System.Collections.Generic.HashSet<vertex * vertex>()
[0..(n-1)]
|> List.map (fun root -> Dijkstra g root |> fun (g,_) -> g)
|> List.map Edges
|> List.map (fun es -> Graph n es)
|> List.map Edges
//> List.fold (fun a b -> List.append a b) []
|> List.fold (fun a b -> List.append a b) []
//|> List.iter (fun (a,b,_) -> ignore(p_e.Add( (min a b, max a b) )))
|> List.iter (fun (a,b,_) -> ignore(p_e.Add( (a,b) )))

g_e.ExceptWith( p_e )
( g_e.Count / 2 ) |> Console.WriteLine
