import Control.Monad
import Data.List
import Data.Maybe
import qualified Data.ByteString.Char8 as B
import qualified Data.Set as S

import qualified Data.Array.IO as A
import qualified Control.Monad as C

newtype UnionFind = UnionFind { unwrap :: A.IOArray Int Int }

newUnionFindTree :: Int -> IO UnionFind
newUnionFindTree n = do
    tree <- A.newArray (1,n) 0 :: IO (A.IOArray Int Int)
    C.forM_ [1..n] $ \i -> A.writeArray tree i i
    return $ UnionFind tree

connectRoot :: UnionFind -> Int -> Int -> IO ()
connectRoot (UnionFind tree) a b = do
    a' <- traverseRoot (UnionFind tree) a
    b' <- traverseRoot (UnionFind tree) b
    A.writeArray tree b' a'
 
traverseRoot :: UnionFind -> Int -> IO Int
traverseRoot (UnionFind tree) i = do
    i' <- A.readArray tree i
    if i == i' then return i
               else do
        r <- traverseRoot (UnionFind tree) i'
        -- rootが分かるのでついでに経路圧縮を行う
        A.writeArray tree i r
        return r

main :: IO ()
main = do
    [n, m] <- map read . words <$> getLine :: IO [Int]
    edges <- replicateM m ((\[a,b]->(a,b)) . map (fst . fromJust . B.readInt) . B.words <$> B.getLine) :: IO [(Int, Int)]
    print . sum =<< forM [1..n] (\i -> do
        let edges' = map snd . filter ((i /=) . fst) $ zip [1..] edges
        tree <- newUnionFindTree n
        forM_ edges' $ \(a,b) -> do
            connectRoot tree a b
        s <- S.size <$> foldM (\s i -> (`S.insert` s) <$> traverseRoot tree i) S.empty [1..n]
        return $ if s == 1 then 0 else 1
        )
