{-# OPTIONS_GHC -O #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST
import Data.List
import Control.Monad.Trans.State.Strict
import Data.Char (isSpace)
import Data.Maybe (fromJust,fromMaybe,isNothing,isJust)
import qualified Data.ByteString.Lazy.Char8 as B

import Data.Array
import Data.Array.ST
import Data.Array.Unsafe

type Parser a = StateT B.ByteString Maybe a

parseInt :: Parser Int
parseInt = StateT (B.readInt . B.dropWhile isSpace)

parseInt2 :: Parser (Int,Int)
parseInt2 = liftM2 (,) parseInt parseInt

parseInt3 :: Parser (Int,Int,Int)
parseInt3 = liftM3 (,,) parseInt parseInt parseInt

parse :: Parser ((Int,Int), [(Int,Int,Int)])
parse = do
    (n,m)<-parseInt2
    rs<-replicateM m parseInt3
    return ((n,m),rs)

main=do
    ((n,m),rs)<-fromJust.evalStateT parse <$> B.getContents
    let da = wf n $ ml n rs
    print $ length $ filter (\(a,b,c)-> fmap (< c) (da!(a,b)) == Just True) rs

ml::Int->[(Int,Int,Int)]->[((Int,Int),Maybe Int)]
ml n rs =unfoldr phi (1,1,rs2)
    where
    rs2 = sort $ concatMap (\(u,v,l)->[(u,v,l),(v,u,l)]) rs
    phi (i,j,a)
        | i==n+1 = Nothing
        | (not.null) a && i==u && j==v = Just (((i,j),Just l), (ni,nj,x))
        | i==j = Just(((i,j),Just 0), (ni,nj,a))
        | i/=j = Just(((i,j),Nothing), (ni,nj,a))
        where
        nj = if j/=n then j+1 else 1
        ni = if j/=n then i else i+1
        ((u,v,l):x) = a

wf ::Int-> [((Int,Int),Maybe Int)] -> Array (Int,Int) (Maybe Int)
wf n g = foldl' psi (array ((1,1),(n,n)) g) $ replicateM 3 [1..n]
    where
    psi :: Array (Int,Int) (Maybe Int) -> [Int] -> Array (Int,Int) (Maybe Int)
    psi d [k,i,j] = runST $ do
        d' <- unsafeThaw d :: ST s (STArray s (Int,Int) (Maybe Int))
        dc <- readArray d' (i,j)
        dn <- liftA2 (+) <$> readArray d' (i,k) <*> readArray d' (k,j)
        when (isNothing dc || liftA2 (>) dc dn == Just True) $ writeArray d' (i,j) dn
        unsafeFreeze d'