input: Write a function to find the optimal solution for the 0-1 knapsack problem using dynamic programming. Given a list of items with their values and weights, and a maximum capacity of the knapsack, the function should return the maximum value that can be achieved by selecting items such that their total weight does not exceed the given capacity.
  
  def knapSack(W, wt, val, n):
    
      # Base Case 
      if n == 0 or W == 0 : 
          return 0
    
      # If weight of the nth item is more 
      # than Knapsack capacity W, then 
      # this item cannot be included in the optimal solution 
      if (wt[n-1] > W): 
          return knapSack(W, wt, val, n-1) 
    
      # return the maximum of two cases: 
      # (1) nth item included 
      # (2) not included 
      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, [10], [60], 1) == 60
  assert knapSack(0, [10, 20], [60, 100], 2) == 0
  assert knapSack(50, [10, 20, 30, 40], [60, 100, 120, 200], 4) == 300
output: def knapSack(W, wt, val, n):
      dp = [[0 for _ in range(W + 1)] for _ in range(n + 1)]
      
      for i in range(1, n + 1):
          for w in range(1, W + 1):
              if 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]