{-# OPTIONS_GHC -O #-}

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)
import qualified Data.ByteString.Lazy.Char8 as B

import Data.Array.ST
import Data.Array.Unboxed
type Dist s = STUArray s (Int,Int) Int

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 rs :: UArray (Int,Int) Int
    --
    print $ length $ filter (f n da) rs

f n da (a,b,c) = all (\s->s1 s /= s2 s) [1..n]
    where
        s1 s = da ! (s,a) + c
        s2 s = da ! (s,b)
--
wf::Int->[(Int,Int,Int)]->UArray (Int,Int) Int
wf n rs = runST $ do
    d <- newArray ((1,1),(n,n)) (maxBound`div`2) :: ST s (STUArray s (Int,Int) Int)
    forM_ rs $ \(u,v,l) -> writeArray d (u,v) l >> writeArray d (v,u) l
    forM_ [(k,i,j)|k<-[1..n],i<-[1..n],j<-[1..n]] $ \(k,i,j) -> do
        dc <- readArray d (i,j)
        dn <- (+) <$> readArray d (i,k) <*> readArray d (k,j)
        when (dc > dn) $ writeArray d (i,j) dn
    freeze d
