input: Write a function to find the optimal solution to solve a knapsack problem using dynamic programming. The function should take in a list of tuples where each tuple represents an item with its value and weight, and an integer representing the capacity of the knapsack. The function should return the maximum value that can be put in the knapsack without exceeding its capacity.
  
  def knapSack(W, wt, val, n):
      if n == 0 or W == 0:
          return 0
      if wt[n-1] > W:
          return knapSack(W, wt, val, n-1)
      else:
          return max(val[n-1] + knapSack(W-wt[n-1], wt, val, n-1), knapSack(W, wt, val, n-1))
  
  assert knapSack(50, [10, 20, 30], [60, 100, 120], 3) == 220
  assert knapSack(30, [10, 20], [60, 100], 2) == 160
  assert knapSack(10, [5, 5], [10, 5], 2) == 10
  assert knapSack(5, [8, 4], [12, 6], 2) == 6
  assert knapSack(0, [10, 20], [60, 100], 2) == 0
output: 
  def knapSack(W, wt, val, n):
      dp = [[0 for _ in range(W + 1)] for _ in range(n + 1)]
      for i in range(n + 1):
          for w in range(W + 1):
              if i == 0 or w == 0:
                  dp[i][w] = 0
              elif wt[i-1] <= w:
                  dp[i][w] = max(val[i-1] + dp[i-1][w-wt[i-1]], dp[i-1][w])
              else:
                  dp[i][w] = dp[i-1][w]
      return dp[n][W]
  