title: Knapsack problem with repeating components for lowest value, to fill (or slightly over) in Python
body: <p>I'm actually trying to find the lowest cost to supply custom medication doses from vials - however while researching, I found the knapsack problem is the best way to describe the issue, in  way that is currently understood.</p>
  
  <p>Breakdown of problem
  *A dose is prescribed based on clinical need.
  *The vials commercially available to make up the dose (and their respective dose) are then considered. The same size vial can be used more than once.
  *The vial / size combination may provide excess (i.e. provide a higher dose than is required) - as that combination works out cheaper than meeting the dose itself, or providing a smaller overage. Therefore overage or wastage is allowed provided the combinations yields the prescribed dose, even if there is wastage.
  *The output should display the qty/ vial combination used and the cost of that combinations.</p>
  
  <p>Example of vials available are 50mg costs $15, 100mg costs $32 and 200mg costs $64</p>
  
  <p>Lets say that a dose of 220mg is prescribed. Some of the possible options to make up the dose are as follows (remembering that the amount of wastage is not relevant provided it provides the cheapest option to make up the dose required.</p>
  
  <pre><code>5 x 50mg = 250mg (30mg over) = $75
  3 x 50mg + 1 x 100mg = 250mg (30mg over) = $77
  2 x 100mg + 1 x 200mg = 400mg (180mg over) = $128
  1 x 50mg + 1 x 200mg = 250mg (30mg over) = $79
  3 x 100mg = 300mg (80mg over) = $96
  </code></pre>
  
  <p>Therefore, we can see that the cheapest option is row1 5x 50mg at $75</p>
  
  <p>If anyone could point me in the right direction then I'd be grateful!</p>
  
  <p>The code below only uses each component once - but I'm lost on how to modify to get it to recycle them.</p>
  
  <pre><code>items = [("ITEM01", 100, 10000), ("ITEM02", 24, 576), \
      ("ITEM03", 24, 576), ("ITEM04", 51, 2500), ("ITEM05", 155, 25)]
  S = sum([item[1] for item in items])    #sums all the weights in the list of items
  dp = [None for i in range(S + 1)]       #list within which cycles through each integer of weights creates a list of "None,"
  dp[0] = []                              #removes the first none from the list
  
  for item in items:                      #for each element in the list of available vials
      for i in range(S, -1, -1):          #counts down from sum of all weights of available vial sizes DOWN TO zero (0) 
          if dp[i] is not None and i + item[1] &lt;= S and \     
      (                                                               #if the long list of Nones - does not read None
          dp[i + item[1]] is None
          or
          sum(set_item[2] for set_item in dp[i]) + item[2]
              &gt; sum(set_item[2] for set_item in dp[i + item[1]])
      ):
              dp[i + item[1]] = dp[i] + [item]
  
  desired_sum = 200                   #desired weight 
  i = j = desired_sum                 # desired sum becomes i and it also becomes j
  
  while i &gt;= 0 and j &lt;= S:            #while desired sum(i) is over 0 and less then sum of weight of all vials in the list.
      if dp[i] is not None:           #if the none list entry at that point is NOT none
          print (dp[i])               #print element from that list that isn't 'None'
          break
      elif dp[j] is not None:         #if None list at desired_weight index is not None
          print (dp[j])               #print the element that isn't none
          break
      else:
          i -= 1                      #else diverge i and j which are originally the same
          j += 1
  </code></pre>