output_description: Print the length of the longest directed path in G.
  
  * * *
input_description: Input is given from Standard Input in the following format:
  
      
      
      N M
      x_1 y_1
      x_2 y_2
      :
      x_M y_M
attempt: # https://atcoder.jp/contests/dp/tasks/dp_g
  import sys
  sys.setrecursionlimit(10**7)
  
  
  class DAG:
      def __init__(self, n):
          # n: num of vertices
          self.n = n
          self.adj = [[] for _ in range(n)]
  
      def addEdge(self, parent, child):
          self.adj[parent].append(child)
  
      def dfs(self, node):
          ans = 0
          for child in self.adj[node]:
              ans = max(ans, 1 + self.dfs(child))
          return ans
  
      def dfsWithMemo(self, node, memo, visited):
          if(visited[node]):
              return memo[node]
          visited[node] = True
          for child in self.adj[node]:
              memo[node] = max(
                  memo[node], 1 + self.dfsWithMemo(child, memo, visited))
          return memo[node]
  
      def dfsWithDp(self, node, dp, visited):
          if(visited[node]):
              return dp[node]
          visited[node] = True
          for child in self.adj[node]:
              if not visited[child]:
                  self.dfsWithDp(child, dp, visited)
              dp[node] = max(dp[node], 1 + self.dfsWithDp(child, dp, visited))
          return dp[node]
  
      # o(n^2) solution
      def findLongestPathNaive(self):
          ans = 0
          for i in range(self.n):
              ans = max(ans, self.dfs(i))
          return ans
  
      # o(n) solution
      def findLongestPathWithMemo(self):
          visited = [False] * self.n
          memo = [0] * self.n
          ans = 0
          for i in range(self.n):
              ans = max(ans, self.dfsWithMemo(i, memo, visited))
          return ans
  
      # O(n) solution
      def findLongestPathWithDp(self):
          visited = [False] * self.n
          dp = [0] * self.n  # dp[i] := longest path starting from vertex i
          ans = 0
          for i in range(self.n):
              ans = max(ans, self.dfsWithDp(i, dp, visited))
          return ans
  
  
  def main():
      N, M = map(int, input().split())
      dag = DAG(N)
      for _ in range(M):
          parent, child = map(lambda i: int(i) - 1, input().split())
          dag.addEdge(parent, child)
      # print(dag.findLongestPathNaive())
      #  print(dag.findLongestPathWithMemo())
       print(dag.findLongestPathWithDp())
  
  
  main()
  
problem_description: Statement
  
  There is a directed graph G with N vertices and M edges. The vertices are
  numbered 1, 2, \ldots, N, and for each i (1 \leq i \leq M), the i-th directed
  edge goes from Vertex x_i to y_i. G **does not contain directed cycles**.
  
  Find the length of the longest directed path in G. Here, the length of a
  directed path is the number of edges in it.
samples: [{"input": "4 5\n    1 2\n    1 3\n    3 2\n    2 4\n    3 4", "output": "3\n    \n\nThe red directed path in the following figure is the longest:\n\n![](https://img.atcoder.jp/dp/longest_0_muffet.png)\n\n* * *"}, {"input": "6 3\n    2 3\n    4 5\n    5 6", "output": "2\n    \n\nThe red directed path in the following figure is the longest:\n\n![](https://img.atcoder.jp/dp/longest_1_muffet.png)\n\n* * *"}, {"input": "5 8\n    5 3\n    2 3\n    2 4\n    5 2\n    5 1\n    1 4\n    4 3\n    1 3", "output": "3\n    \n\nThe red directed path in the following figure is one of the longest:\n\n![](https://img.atcoder.jp/dp/longest_2_muffet.png)"}]