input: Write a python function to solve the knapsack problem using dynamic programming.
  assert knapsack([(10, 5), (5, 7), (8, 3), (9, 9)], 16) == 21
  assert knapsack([(20, 10), (30, 20), (40, 30)], 50) == 50
  assert knapsack([(5, 3), (10, 4), (15, 8)], 10) == 15
output: def knapsack(items, capacity):
      n = len(items)
      dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]
      
      for i in range(1, n + 1):
          weight, value = items[i - 1]
          for w in range(1, capacity + 1):
              if weight <= w:
                  dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weight] + value)
              else:
                  dp[i][w] = dp[i - 1][w]
                  
      return dp[n][capacity]