input: Write a function to count the number of unique paths from the top-left corner to the bottom-right corner of an m x n grid. The only moves allowed are moving down or moving right. If the dimensions of the grid are invalid or if it is impossible to reach the destination, return 0. If the input grid is empty, return 0. Use dynamic programming to solve this problem.
  def num_unique_paths(m, n):
      dp = [[0 for x in range(m)] for y in range(n)] 
    
      # Count of paths to reach any
      # cell in first column is 1  
      for i in range(n): 
          dp[i][0] = 1
    
      # Count of paths to reach any
      # cell in first column is 1  
      for j in range(m): 
          dp[0][j] = 1
    
      # Calculate count of paths for other 
      # cells in bottom-up manner using
      # the recursive solution 
      for i in range(1, n): 
          for j in range(1, m): 
    
              # By uncommenting the last
              # part the code calculatest he total
              # possible paths if the diagonal 
              # Movements are allowed 
              dp[i][j] = dp[i-1][j] + dp[i][j-1]# + dp[i-1][j-1]
    
      return dp[n-1][m-1]
      
  assert num_unique_paths(2, 3)==3
  assert num_unique_paths(7, 3)==28
  assert num_unique_paths(0, 0)==0
  assert num_unique_paths(1, 1)==1
  assert num_unique_paths(3, 3)==6
  assert num_unique_paths(1, 0)==0
  assert num_unique_paths(4, 2)==4
  assert num_unique_paths(0, 5)==0
output: def num_unique_paths(m, n):
      if m <= 0 or n <= 0:
          return 0
      dp = [[0 for x in range(m)] for y in range(n)]
      for i in range(n):
          dp[i][0] = 1
      for j in range(m):
          dp[0][j] = 1
      for i in range(1, n):
          for j in range(1, m):
              dp[i][j] = dp[i-1][j] + dp[i][j-1]
      return dp[n-1][m-1]