module directed_graph_mod
    use,intrinsic :: iso_fortran_env
    implicit none
    type node
        integer(int32), allocatable:: to(:)
        integer(int32):: i
    end type
contains
    subroutine init_dg(n)
        type(node):: n
        allocate(n%to(0))
        n%i=0
    end subroutine

    subroutine regist(n,i)
        type(node):: n
        integer(int32):: i
        if (n%i+1 > size(n%to))call add(n)
        n%i=n%i+1
        n%to(n%i) = i
    end subroutine

    subroutine add(n)
        type(node):: n
        integer(int32), allocatable:: tmp(:)
        integer(int32):: l

        l=size(n%to)
        allocate(tmp(l))
        tmp(:) = n%to(:)
        deallocate(n%to)
        allocate(n%to(max(1,2*l)))
        n%to(1:l) = tmp(:)
        deallocate(tmp)
    end subroutine
end module directed_graph_mod

program name
    use,intrinsic :: iso_fortran_env
    use:: directed_graph_mod
    implicit none

    integer(int32):: n,m,i,ans=0
    integer(int32), allocatable:: dp(:)
    type(node),allocatable:: g(:)

    read*, n,m
    allocate(g(n))
    initialized_graph : do i = 1, n
        call init_dg(g(i))
    end do initialized_graph
    allocate(dp(n),source=-1)
    block
        integer(int32):: x,y
        do i=1,m
            read*, x,y
            call regist(g(x),y)
        end do
    end block
    
    do i=1,n
        ans=max(ans,dfs(i))
    end do

    ! print*, dp(:)
    print'(i0)', ans

contains
    recursive function dfs(num) result(ret)
        integer(int32):: num,ret
        integer(int32):: i, dst
        ret=0
        if (dp(num) /= -1) then
            ret = dp(num)
            return
        end if

        i=1
        do i=1,g(num)%i
            dst = g(num)%to(i)
            ret=max(ret,dfs(dst)+1)
        end do
        dp(num) = ret
    end function
end program name