input: Write a function to find the optimal solution to solve a knapsack problem using dynamic programming. The function takes in the capacity of the knapsack and lists of item values and weights, and returns the maximum value that can be achieved.
  
  def knapsack_dp(capacity, weights, values):
      n = len(values)
      dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]
      
      for i in range(1, n + 1):
          for w in range(1, capacity + 1):
              if weights[i-1] <= w:
                  dp[i][w] = max(values[i-1] + dp[i-1][w-weights[i-1]], dp[i-1][w])
              else:
                  dp[i][w] = dp[i-1][w]
      
      return dp[n][capacity]
  
  assert knapsack_dp(50, [10, 20, 30], [60, 100, 120]) == 220
  assert knapsack_dp(40, [10, 20, 30], [60, 100, 120]) == 180
  assert knapsack_dp(10, [10, 20, 30], [60, 100, 120]) == 60
  assert knapsack_dp(0, [10, 20, 30], [60, 100, 120]) == 0
  assert knapsack_dp(50, [], []) == 0
output: def knapsack_dp(capacity, weights, values):
      n = len(values)
      dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]
      
      for i in range(1, n + 1):
          for w in range(1, capacity + 1):
              if weights[i-1] <= w:
                  dp[i][w] = max(values[i-1] + dp[i-1][w-weights[i-1]], dp[i-1][w])
              else:
                  dp[i][w] = dp[i-1][w]
      
      return dp[n][capacity]