Solution to the 0/1 knapsack in PythonDynamic programming knapsack solutionKnapsack branch and bound: forward...

How to run a prison with the smallest amount of guards?

Can the discrete variable be a negative number?

What is the difference between "behavior" and "behaviour"?

How does the UK government determine the size of a mandate?

Different result between scanning in Epson's "color negative film" mode and scanning in positive -> invert curve in post?

What can we do to stop prior company from asking us questions?

How can I kill an app using Terminal?

A Rare Riley Riddle

Opposite of a diet

Did Dumbledore lie to Harry about how long he had James Potter's invisibility cloak when he was examining it? If so, why?

What does 算不上 mean in 算不上太美好的日子?

Implement the Thanos sorting algorithm

Sequence of Tenses: Translating the subjunctive

Why didn't Theresa May consult with Parliament before negotiating a deal with the EU?

How do scammers retract money, while you can’t?

Term for the "extreme-extension" version of a straw man fallacy?

Is there a good way to store credentials outside of a password manager?

How do I find the solutions of the following equation?

Arithmetic mean geometric mean inequality unclear

Why does indent disappear in lists?

Why Were Madagascar and New Zealand Discovered So Late?

How to Reset Passwords on Multiple Websites Easily?

Is there a problem with hiding "forgot password" until it's needed?

What is paid subscription needed for in Mortal Kombat 11?



Solution to the 0/1 knapsack in Python


Dynamic programming knapsack solutionKnapsack branch and bound: forward filterFunctional Knapsack Problem in PythonPython Knapsack problem using branch and bound algorithmPython Knapsack problem: greedyFractional KnapsackFractional Knapsack in JavaKnapsack algorithm in JavaScript - Integer weights and values0-1 Knapsack problem - implementationKnapsack problem with duplicate elements













4












$begingroup$


So I made a version for the 0/1 knapsack problem myself (using matrix dynamic programming algorithm). Given a list of items with name, value, and weight, my function computes correctly the optimal value with total weight <= allowed weight.



I don't know if my code is clean and pythonic enough, I would greatly appreciate it if you give me some comments, thanks.



def knapsack(W, items):
"""
Given a list of items with name, value and weight.
Return the optimal value with total weight <= allowed weight and
list of picked items.
"""
n = len(items)
k = [[0 for x in range(W+1)] for x in range(n+1)]

for i in range(n+1):
for w in range(W+1):
if i == 0 or w == 0:
k[i][w] = 0
elif items[i-1][2] <= w:
k[i][w] = max(items[i-1][1] + k[i-1][w-items[i-1][2]], k[i-1][w])
else:
k[i][w] = k[i-1][w]

picked = []
set_trace(k, n, W, items, picked)
return k[n][W], picked

# find which item are picked
def set_trace(k, n, W, items, picked):
for i in range(n, 0, -1):
if k[i][W] != k[i-1][W]:
picked.append(items[i-1])
set_trace(k, i-1, W-items[i-1][2], items, picked)
break

if __name__ == '__main__':
items = [('A', 1, 1), ('B', 4, 3), ('C', 5, 4), ('D', 7, 5)]
max_value, picked = knapsack(7, items)
print("Maximum value:", max_value)
print("Name", "Value", "Weight")
for item in reversed(picked):
print(item[0], ' '*2, item[1], ' '*3, item[2])


Output:



Maximum value: 9
Name Value Weight
B 4 3
C 5 4









share|improve this question











$endgroup$

















    4












    $begingroup$


    So I made a version for the 0/1 knapsack problem myself (using matrix dynamic programming algorithm). Given a list of items with name, value, and weight, my function computes correctly the optimal value with total weight <= allowed weight.



    I don't know if my code is clean and pythonic enough, I would greatly appreciate it if you give me some comments, thanks.



    def knapsack(W, items):
    """
    Given a list of items with name, value and weight.
    Return the optimal value with total weight <= allowed weight and
    list of picked items.
    """
    n = len(items)
    k = [[0 for x in range(W+1)] for x in range(n+1)]

    for i in range(n+1):
    for w in range(W+1):
    if i == 0 or w == 0:
    k[i][w] = 0
    elif items[i-1][2] <= w:
    k[i][w] = max(items[i-1][1] + k[i-1][w-items[i-1][2]], k[i-1][w])
    else:
    k[i][w] = k[i-1][w]

    picked = []
    set_trace(k, n, W, items, picked)
    return k[n][W], picked

    # find which item are picked
    def set_trace(k, n, W, items, picked):
    for i in range(n, 0, -1):
    if k[i][W] != k[i-1][W]:
    picked.append(items[i-1])
    set_trace(k, i-1, W-items[i-1][2], items, picked)
    break

    if __name__ == '__main__':
    items = [('A', 1, 1), ('B', 4, 3), ('C', 5, 4), ('D', 7, 5)]
    max_value, picked = knapsack(7, items)
    print("Maximum value:", max_value)
    print("Name", "Value", "Weight")
    for item in reversed(picked):
    print(item[0], ' '*2, item[1], ' '*3, item[2])


    Output:



    Maximum value: 9
    Name Value Weight
    B 4 3
    C 5 4









    share|improve this question











    $endgroup$















      4












      4








      4


      1



      $begingroup$


      So I made a version for the 0/1 knapsack problem myself (using matrix dynamic programming algorithm). Given a list of items with name, value, and weight, my function computes correctly the optimal value with total weight <= allowed weight.



      I don't know if my code is clean and pythonic enough, I would greatly appreciate it if you give me some comments, thanks.



      def knapsack(W, items):
      """
      Given a list of items with name, value and weight.
      Return the optimal value with total weight <= allowed weight and
      list of picked items.
      """
      n = len(items)
      k = [[0 for x in range(W+1)] for x in range(n+1)]

      for i in range(n+1):
      for w in range(W+1):
      if i == 0 or w == 0:
      k[i][w] = 0
      elif items[i-1][2] <= w:
      k[i][w] = max(items[i-1][1] + k[i-1][w-items[i-1][2]], k[i-1][w])
      else:
      k[i][w] = k[i-1][w]

      picked = []
      set_trace(k, n, W, items, picked)
      return k[n][W], picked

      # find which item are picked
      def set_trace(k, n, W, items, picked):
      for i in range(n, 0, -1):
      if k[i][W] != k[i-1][W]:
      picked.append(items[i-1])
      set_trace(k, i-1, W-items[i-1][2], items, picked)
      break

      if __name__ == '__main__':
      items = [('A', 1, 1), ('B', 4, 3), ('C', 5, 4), ('D', 7, 5)]
      max_value, picked = knapsack(7, items)
      print("Maximum value:", max_value)
      print("Name", "Value", "Weight")
      for item in reversed(picked):
      print(item[0], ' '*2, item[1], ' '*3, item[2])


      Output:



      Maximum value: 9
      Name Value Weight
      B 4 3
      C 5 4









      share|improve this question











      $endgroup$




      So I made a version for the 0/1 knapsack problem myself (using matrix dynamic programming algorithm). Given a list of items with name, value, and weight, my function computes correctly the optimal value with total weight <= allowed weight.



      I don't know if my code is clean and pythonic enough, I would greatly appreciate it if you give me some comments, thanks.



      def knapsack(W, items):
      """
      Given a list of items with name, value and weight.
      Return the optimal value with total weight <= allowed weight and
      list of picked items.
      """
      n = len(items)
      k = [[0 for x in range(W+1)] for x in range(n+1)]

      for i in range(n+1):
      for w in range(W+1):
      if i == 0 or w == 0:
      k[i][w] = 0
      elif items[i-1][2] <= w:
      k[i][w] = max(items[i-1][1] + k[i-1][w-items[i-1][2]], k[i-1][w])
      else:
      k[i][w] = k[i-1][w]

      picked = []
      set_trace(k, n, W, items, picked)
      return k[n][W], picked

      # find which item are picked
      def set_trace(k, n, W, items, picked):
      for i in range(n, 0, -1):
      if k[i][W] != k[i-1][W]:
      picked.append(items[i-1])
      set_trace(k, i-1, W-items[i-1][2], items, picked)
      break

      if __name__ == '__main__':
      items = [('A', 1, 1), ('B', 4, 3), ('C', 5, 4), ('D', 7, 5)]
      max_value, picked = knapsack(7, items)
      print("Maximum value:", max_value)
      print("Name", "Value", "Weight")
      for item in reversed(picked):
      print(item[0], ' '*2, item[1], ' '*3, item[2])


      Output:



      Maximum value: 9
      Name Value Weight
      B 4 3
      C 5 4






      python algorithm






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 11 '16 at 13:21

























      asked Apr 11 '16 at 12:04







      user102577





























          2 Answers
          2






          active

          oldest

          votes


















          1












          $begingroup$

          Kudos for using list comprehensions. However picked = []; set_trace(k, n, W, items, picked) and picked.append(items[i-1]) doesn't feel as good.



          One could expect set_trace to build the list and return it. Even better, would be to picked = list(set_trace(k, n, W, items)), meaning set_trace would be a generator (with a pretty terrible name).



          In order to do so, you first have to come to the conclusion that the recursion is really not necessary. All you do, in that recursive call, is continue the iteration at the next step with a different W. And that's it, you break. You could have just replace these two lines with W -= items[i-1][2]. Doing so, you could replace the append with a yield and you have your generator:



          def set_trace(k, n, W, items):
          for i in range(n, 0, -1):
          if k[i][W] != k[i-1][W]:
          yield items[i-1]
          W -= items[i-1][2]


          this lets you define picked = list(set_trace(k, n, W, items)).



          However, n is len(items) so you might as well not pass it as a parameter and compute it at the beginning of the function.





          You can also get much better readability by improving your naming. I understand that you named your variables based of the math theory that this problem relly on, but single letter variable names are a poor choice.



          Same for using a simple tuple to store your items: it doesn't convey meaning. Use a namedtuple instead.



          Last thing, since you are skipping the first row and first column of k, you can use slices and the enumerate builtin to avoid using so much brackets; you can also improve set_trace in such a way by using zip to create pairwise values of potential weights:



          from collections import namedtuple

          Item = namedtuple('Item', 'name value weight')

          def knapsack(allowed_weight, items):
          """
          Given a list of items with name, value and weight.
          Return the optimal value with total weight <= allowed weight and
          list of picked items.
          """
          k = [
          [0 for x in range(allowed_weight + 1)]
          for x in range(len(items) + 1)
          ]

          for next_idx, (item, weights) in enumerate(zip(items, k), 1):
          for w, current_weight in enumerate(weights[1:], 1):
          if item.weight <= w:
          k[next_idx][w] = max(
          item.value + weights[w - item.weight],
          current_weight
          )
          else:
          k[next_idx][w] = current_weight

          return k[-1][-1], list(fetch_items(k, allowed_weight, items))

          # find which item are picked
          def fetch_items(k, allowed_weight, items):
          for item, weights_p, weights_n in zip(items[::-1], k[-2::-1], k[::-1]):
          if weights_n[allowed_weight] != weights_p[allowed_weight]:
          yield item
          allowed_weight -= item.weight

          if __name__ == '__main__':
          items = [
          Item('A', 1, 1),
          Item('B', 4, 3),
          Item('C', 5, 4),
          Item('D', 7, 5),
          ]
          max_value, picked = knapsack(7, items)
          print("Maximum value:", max_value)
          print("Name", "Value", "Weight")
          for item in reversed(picked):
          print(item.name, ' '*2, item.value, ' '*3, item.weight)





          share|improve this answer









          $endgroup$





















            0












            $begingroup$

            Python Code for 1-0 Knapsack is:-



            import numpy as np

            def Knapsack(W, wt, profit):
            print('-------------------------------------------------------------')
            print('Total Weight: %s' %W)
            print('Weights: %s' %wt)
            print('Profit: %s' %profit)
            mat = np.zeros((len(wt)+1, W+1))
            for i in range(0,len(wt)+1):
            for w in range(0,W+1):
            if i==0 or w==0:
            mat[i][w] = 0
            elif wt[i-1]>w:
            mat[i][w] = mat[i-1][w]
            else:
            mat[i][w] = max(mat[i-1][w],(profit[i-1]+mat[i-1][w-wt[i-1]]))

            k=W
            list =[]
            for i in range(len(wt),-1,-1):
            if mat[i, k] != mat[i - 1, k]:
            k = k - wt[i-1]
            if i!=0:
            list.append(i)
            print('-------------------------------------------------------------')
            print('Rows: items and columns: weight.')
            print(mat)
            #i have added this below code to transpose if wanted
            #transpose = zip(*mat)
            #for row in transpose:
            # print(row)
            print('-------------------------------------------------------------')
            print('Maximum Profit: %s' %mat[len(wt)][W])
            print('-------------------------------------------------------------')
            print('Items Added')
            print(list)

            def main():
            W = 5
            Wt =[3,2,4,1]
            Pt =[100,20,60,40]
            Knapsack(W,Wt,Pt)

            main()


            OUTPUT:-



            -------------------------------------------------------------
            Total Weight: 5
            Weights: [3, 2, 4, 1]
            Profit: [100, 20, 60, 40]
            -------------------------------------------------------------
            Rows: items and columns: weight.
            [[ 0. 0. 0. 0. 0. 0.]
            [ 0. 0. 0. 100. 100. 100.]
            [ 0. 0. 20. 100. 100. 120.]
            [ 0. 0. 20. 100. 100. 120.]
            [ 0. 40. 40. 100. 140. 140.]]
            -------------------------------------------------------------
            Maximum Profit: 140.0
            -------------------------------------------------------------
            Items Added
            [4, 1]




            share








            New contributor




            Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
            Check out our Code of Conduct.






            $endgroup$













              Your Answer





              StackExchange.ifUsing("editor", function () {
              return StackExchange.using("mathjaxEditing", function () {
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              });
              });
              }, "mathjax-editing");

              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "196"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f125374%2fsolution-to-the-0-1-knapsack-in-python%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown
























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              1












              $begingroup$

              Kudos for using list comprehensions. However picked = []; set_trace(k, n, W, items, picked) and picked.append(items[i-1]) doesn't feel as good.



              One could expect set_trace to build the list and return it. Even better, would be to picked = list(set_trace(k, n, W, items)), meaning set_trace would be a generator (with a pretty terrible name).



              In order to do so, you first have to come to the conclusion that the recursion is really not necessary. All you do, in that recursive call, is continue the iteration at the next step with a different W. And that's it, you break. You could have just replace these two lines with W -= items[i-1][2]. Doing so, you could replace the append with a yield and you have your generator:



              def set_trace(k, n, W, items):
              for i in range(n, 0, -1):
              if k[i][W] != k[i-1][W]:
              yield items[i-1]
              W -= items[i-1][2]


              this lets you define picked = list(set_trace(k, n, W, items)).



              However, n is len(items) so you might as well not pass it as a parameter and compute it at the beginning of the function.





              You can also get much better readability by improving your naming. I understand that you named your variables based of the math theory that this problem relly on, but single letter variable names are a poor choice.



              Same for using a simple tuple to store your items: it doesn't convey meaning. Use a namedtuple instead.



              Last thing, since you are skipping the first row and first column of k, you can use slices and the enumerate builtin to avoid using so much brackets; you can also improve set_trace in such a way by using zip to create pairwise values of potential weights:



              from collections import namedtuple

              Item = namedtuple('Item', 'name value weight')

              def knapsack(allowed_weight, items):
              """
              Given a list of items with name, value and weight.
              Return the optimal value with total weight <= allowed weight and
              list of picked items.
              """
              k = [
              [0 for x in range(allowed_weight + 1)]
              for x in range(len(items) + 1)
              ]

              for next_idx, (item, weights) in enumerate(zip(items, k), 1):
              for w, current_weight in enumerate(weights[1:], 1):
              if item.weight <= w:
              k[next_idx][w] = max(
              item.value + weights[w - item.weight],
              current_weight
              )
              else:
              k[next_idx][w] = current_weight

              return k[-1][-1], list(fetch_items(k, allowed_weight, items))

              # find which item are picked
              def fetch_items(k, allowed_weight, items):
              for item, weights_p, weights_n in zip(items[::-1], k[-2::-1], k[::-1]):
              if weights_n[allowed_weight] != weights_p[allowed_weight]:
              yield item
              allowed_weight -= item.weight

              if __name__ == '__main__':
              items = [
              Item('A', 1, 1),
              Item('B', 4, 3),
              Item('C', 5, 4),
              Item('D', 7, 5),
              ]
              max_value, picked = knapsack(7, items)
              print("Maximum value:", max_value)
              print("Name", "Value", "Weight")
              for item in reversed(picked):
              print(item.name, ' '*2, item.value, ' '*3, item.weight)





              share|improve this answer









              $endgroup$


















                1












                $begingroup$

                Kudos for using list comprehensions. However picked = []; set_trace(k, n, W, items, picked) and picked.append(items[i-1]) doesn't feel as good.



                One could expect set_trace to build the list and return it. Even better, would be to picked = list(set_trace(k, n, W, items)), meaning set_trace would be a generator (with a pretty terrible name).



                In order to do so, you first have to come to the conclusion that the recursion is really not necessary. All you do, in that recursive call, is continue the iteration at the next step with a different W. And that's it, you break. You could have just replace these two lines with W -= items[i-1][2]. Doing so, you could replace the append with a yield and you have your generator:



                def set_trace(k, n, W, items):
                for i in range(n, 0, -1):
                if k[i][W] != k[i-1][W]:
                yield items[i-1]
                W -= items[i-1][2]


                this lets you define picked = list(set_trace(k, n, W, items)).



                However, n is len(items) so you might as well not pass it as a parameter and compute it at the beginning of the function.





                You can also get much better readability by improving your naming. I understand that you named your variables based of the math theory that this problem relly on, but single letter variable names are a poor choice.



                Same for using a simple tuple to store your items: it doesn't convey meaning. Use a namedtuple instead.



                Last thing, since you are skipping the first row and first column of k, you can use slices and the enumerate builtin to avoid using so much brackets; you can also improve set_trace in such a way by using zip to create pairwise values of potential weights:



                from collections import namedtuple

                Item = namedtuple('Item', 'name value weight')

                def knapsack(allowed_weight, items):
                """
                Given a list of items with name, value and weight.
                Return the optimal value with total weight <= allowed weight and
                list of picked items.
                """
                k = [
                [0 for x in range(allowed_weight + 1)]
                for x in range(len(items) + 1)
                ]

                for next_idx, (item, weights) in enumerate(zip(items, k), 1):
                for w, current_weight in enumerate(weights[1:], 1):
                if item.weight <= w:
                k[next_idx][w] = max(
                item.value + weights[w - item.weight],
                current_weight
                )
                else:
                k[next_idx][w] = current_weight

                return k[-1][-1], list(fetch_items(k, allowed_weight, items))

                # find which item are picked
                def fetch_items(k, allowed_weight, items):
                for item, weights_p, weights_n in zip(items[::-1], k[-2::-1], k[::-1]):
                if weights_n[allowed_weight] != weights_p[allowed_weight]:
                yield item
                allowed_weight -= item.weight

                if __name__ == '__main__':
                items = [
                Item('A', 1, 1),
                Item('B', 4, 3),
                Item('C', 5, 4),
                Item('D', 7, 5),
                ]
                max_value, picked = knapsack(7, items)
                print("Maximum value:", max_value)
                print("Name", "Value", "Weight")
                for item in reversed(picked):
                print(item.name, ' '*2, item.value, ' '*3, item.weight)





                share|improve this answer









                $endgroup$
















                  1












                  1








                  1





                  $begingroup$

                  Kudos for using list comprehensions. However picked = []; set_trace(k, n, W, items, picked) and picked.append(items[i-1]) doesn't feel as good.



                  One could expect set_trace to build the list and return it. Even better, would be to picked = list(set_trace(k, n, W, items)), meaning set_trace would be a generator (with a pretty terrible name).



                  In order to do so, you first have to come to the conclusion that the recursion is really not necessary. All you do, in that recursive call, is continue the iteration at the next step with a different W. And that's it, you break. You could have just replace these two lines with W -= items[i-1][2]. Doing so, you could replace the append with a yield and you have your generator:



                  def set_trace(k, n, W, items):
                  for i in range(n, 0, -1):
                  if k[i][W] != k[i-1][W]:
                  yield items[i-1]
                  W -= items[i-1][2]


                  this lets you define picked = list(set_trace(k, n, W, items)).



                  However, n is len(items) so you might as well not pass it as a parameter and compute it at the beginning of the function.





                  You can also get much better readability by improving your naming. I understand that you named your variables based of the math theory that this problem relly on, but single letter variable names are a poor choice.



                  Same for using a simple tuple to store your items: it doesn't convey meaning. Use a namedtuple instead.



                  Last thing, since you are skipping the first row and first column of k, you can use slices and the enumerate builtin to avoid using so much brackets; you can also improve set_trace in such a way by using zip to create pairwise values of potential weights:



                  from collections import namedtuple

                  Item = namedtuple('Item', 'name value weight')

                  def knapsack(allowed_weight, items):
                  """
                  Given a list of items with name, value and weight.
                  Return the optimal value with total weight <= allowed weight and
                  list of picked items.
                  """
                  k = [
                  [0 for x in range(allowed_weight + 1)]
                  for x in range(len(items) + 1)
                  ]

                  for next_idx, (item, weights) in enumerate(zip(items, k), 1):
                  for w, current_weight in enumerate(weights[1:], 1):
                  if item.weight <= w:
                  k[next_idx][w] = max(
                  item.value + weights[w - item.weight],
                  current_weight
                  )
                  else:
                  k[next_idx][w] = current_weight

                  return k[-1][-1], list(fetch_items(k, allowed_weight, items))

                  # find which item are picked
                  def fetch_items(k, allowed_weight, items):
                  for item, weights_p, weights_n in zip(items[::-1], k[-2::-1], k[::-1]):
                  if weights_n[allowed_weight] != weights_p[allowed_weight]:
                  yield item
                  allowed_weight -= item.weight

                  if __name__ == '__main__':
                  items = [
                  Item('A', 1, 1),
                  Item('B', 4, 3),
                  Item('C', 5, 4),
                  Item('D', 7, 5),
                  ]
                  max_value, picked = knapsack(7, items)
                  print("Maximum value:", max_value)
                  print("Name", "Value", "Weight")
                  for item in reversed(picked):
                  print(item.name, ' '*2, item.value, ' '*3, item.weight)





                  share|improve this answer









                  $endgroup$



                  Kudos for using list comprehensions. However picked = []; set_trace(k, n, W, items, picked) and picked.append(items[i-1]) doesn't feel as good.



                  One could expect set_trace to build the list and return it. Even better, would be to picked = list(set_trace(k, n, W, items)), meaning set_trace would be a generator (with a pretty terrible name).



                  In order to do so, you first have to come to the conclusion that the recursion is really not necessary. All you do, in that recursive call, is continue the iteration at the next step with a different W. And that's it, you break. You could have just replace these two lines with W -= items[i-1][2]. Doing so, you could replace the append with a yield and you have your generator:



                  def set_trace(k, n, W, items):
                  for i in range(n, 0, -1):
                  if k[i][W] != k[i-1][W]:
                  yield items[i-1]
                  W -= items[i-1][2]


                  this lets you define picked = list(set_trace(k, n, W, items)).



                  However, n is len(items) so you might as well not pass it as a parameter and compute it at the beginning of the function.





                  You can also get much better readability by improving your naming. I understand that you named your variables based of the math theory that this problem relly on, but single letter variable names are a poor choice.



                  Same for using a simple tuple to store your items: it doesn't convey meaning. Use a namedtuple instead.



                  Last thing, since you are skipping the first row and first column of k, you can use slices and the enumerate builtin to avoid using so much brackets; you can also improve set_trace in such a way by using zip to create pairwise values of potential weights:



                  from collections import namedtuple

                  Item = namedtuple('Item', 'name value weight')

                  def knapsack(allowed_weight, items):
                  """
                  Given a list of items with name, value and weight.
                  Return the optimal value with total weight <= allowed weight and
                  list of picked items.
                  """
                  k = [
                  [0 for x in range(allowed_weight + 1)]
                  for x in range(len(items) + 1)
                  ]

                  for next_idx, (item, weights) in enumerate(zip(items, k), 1):
                  for w, current_weight in enumerate(weights[1:], 1):
                  if item.weight <= w:
                  k[next_idx][w] = max(
                  item.value + weights[w - item.weight],
                  current_weight
                  )
                  else:
                  k[next_idx][w] = current_weight

                  return k[-1][-1], list(fetch_items(k, allowed_weight, items))

                  # find which item are picked
                  def fetch_items(k, allowed_weight, items):
                  for item, weights_p, weights_n in zip(items[::-1], k[-2::-1], k[::-1]):
                  if weights_n[allowed_weight] != weights_p[allowed_weight]:
                  yield item
                  allowed_weight -= item.weight

                  if __name__ == '__main__':
                  items = [
                  Item('A', 1, 1),
                  Item('B', 4, 3),
                  Item('C', 5, 4),
                  Item('D', 7, 5),
                  ]
                  max_value, picked = knapsack(7, items)
                  print("Maximum value:", max_value)
                  print("Name", "Value", "Weight")
                  for item in reversed(picked):
                  print(item.name, ' '*2, item.value, ' '*3, item.weight)






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Apr 11 '16 at 15:01









                  Mathias EttingerMathias Ettinger

                  25.1k33185




                  25.1k33185

























                      0












                      $begingroup$

                      Python Code for 1-0 Knapsack is:-



                      import numpy as np

                      def Knapsack(W, wt, profit):
                      print('-------------------------------------------------------------')
                      print('Total Weight: %s' %W)
                      print('Weights: %s' %wt)
                      print('Profit: %s' %profit)
                      mat = np.zeros((len(wt)+1, W+1))
                      for i in range(0,len(wt)+1):
                      for w in range(0,W+1):
                      if i==0 or w==0:
                      mat[i][w] = 0
                      elif wt[i-1]>w:
                      mat[i][w] = mat[i-1][w]
                      else:
                      mat[i][w] = max(mat[i-1][w],(profit[i-1]+mat[i-1][w-wt[i-1]]))

                      k=W
                      list =[]
                      for i in range(len(wt),-1,-1):
                      if mat[i, k] != mat[i - 1, k]:
                      k = k - wt[i-1]
                      if i!=0:
                      list.append(i)
                      print('-------------------------------------------------------------')
                      print('Rows: items and columns: weight.')
                      print(mat)
                      #i have added this below code to transpose if wanted
                      #transpose = zip(*mat)
                      #for row in transpose:
                      # print(row)
                      print('-------------------------------------------------------------')
                      print('Maximum Profit: %s' %mat[len(wt)][W])
                      print('-------------------------------------------------------------')
                      print('Items Added')
                      print(list)

                      def main():
                      W = 5
                      Wt =[3,2,4,1]
                      Pt =[100,20,60,40]
                      Knapsack(W,Wt,Pt)

                      main()


                      OUTPUT:-



                      -------------------------------------------------------------
                      Total Weight: 5
                      Weights: [3, 2, 4, 1]
                      Profit: [100, 20, 60, 40]
                      -------------------------------------------------------------
                      Rows: items and columns: weight.
                      [[ 0. 0. 0. 0. 0. 0.]
                      [ 0. 0. 0. 100. 100. 100.]
                      [ 0. 0. 20. 100. 100. 120.]
                      [ 0. 0. 20. 100. 100. 120.]
                      [ 0. 40. 40. 100. 140. 140.]]
                      -------------------------------------------------------------
                      Maximum Profit: 140.0
                      -------------------------------------------------------------
                      Items Added
                      [4, 1]




                      share








                      New contributor




                      Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                      Check out our Code of Conduct.






                      $endgroup$


















                        0












                        $begingroup$

                        Python Code for 1-0 Knapsack is:-



                        import numpy as np

                        def Knapsack(W, wt, profit):
                        print('-------------------------------------------------------------')
                        print('Total Weight: %s' %W)
                        print('Weights: %s' %wt)
                        print('Profit: %s' %profit)
                        mat = np.zeros((len(wt)+1, W+1))
                        for i in range(0,len(wt)+1):
                        for w in range(0,W+1):
                        if i==0 or w==0:
                        mat[i][w] = 0
                        elif wt[i-1]>w:
                        mat[i][w] = mat[i-1][w]
                        else:
                        mat[i][w] = max(mat[i-1][w],(profit[i-1]+mat[i-1][w-wt[i-1]]))

                        k=W
                        list =[]
                        for i in range(len(wt),-1,-1):
                        if mat[i, k] != mat[i - 1, k]:
                        k = k - wt[i-1]
                        if i!=0:
                        list.append(i)
                        print('-------------------------------------------------------------')
                        print('Rows: items and columns: weight.')
                        print(mat)
                        #i have added this below code to transpose if wanted
                        #transpose = zip(*mat)
                        #for row in transpose:
                        # print(row)
                        print('-------------------------------------------------------------')
                        print('Maximum Profit: %s' %mat[len(wt)][W])
                        print('-------------------------------------------------------------')
                        print('Items Added')
                        print(list)

                        def main():
                        W = 5
                        Wt =[3,2,4,1]
                        Pt =[100,20,60,40]
                        Knapsack(W,Wt,Pt)

                        main()


                        OUTPUT:-



                        -------------------------------------------------------------
                        Total Weight: 5
                        Weights: [3, 2, 4, 1]
                        Profit: [100, 20, 60, 40]
                        -------------------------------------------------------------
                        Rows: items and columns: weight.
                        [[ 0. 0. 0. 0. 0. 0.]
                        [ 0. 0. 0. 100. 100. 100.]
                        [ 0. 0. 20. 100. 100. 120.]
                        [ 0. 0. 20. 100. 100. 120.]
                        [ 0. 40. 40. 100. 140. 140.]]
                        -------------------------------------------------------------
                        Maximum Profit: 140.0
                        -------------------------------------------------------------
                        Items Added
                        [4, 1]




                        share








                        New contributor




                        Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.






                        $endgroup$
















                          0












                          0








                          0





                          $begingroup$

                          Python Code for 1-0 Knapsack is:-



                          import numpy as np

                          def Knapsack(W, wt, profit):
                          print('-------------------------------------------------------------')
                          print('Total Weight: %s' %W)
                          print('Weights: %s' %wt)
                          print('Profit: %s' %profit)
                          mat = np.zeros((len(wt)+1, W+1))
                          for i in range(0,len(wt)+1):
                          for w in range(0,W+1):
                          if i==0 or w==0:
                          mat[i][w] = 0
                          elif wt[i-1]>w:
                          mat[i][w] = mat[i-1][w]
                          else:
                          mat[i][w] = max(mat[i-1][w],(profit[i-1]+mat[i-1][w-wt[i-1]]))

                          k=W
                          list =[]
                          for i in range(len(wt),-1,-1):
                          if mat[i, k] != mat[i - 1, k]:
                          k = k - wt[i-1]
                          if i!=0:
                          list.append(i)
                          print('-------------------------------------------------------------')
                          print('Rows: items and columns: weight.')
                          print(mat)
                          #i have added this below code to transpose if wanted
                          #transpose = zip(*mat)
                          #for row in transpose:
                          # print(row)
                          print('-------------------------------------------------------------')
                          print('Maximum Profit: %s' %mat[len(wt)][W])
                          print('-------------------------------------------------------------')
                          print('Items Added')
                          print(list)

                          def main():
                          W = 5
                          Wt =[3,2,4,1]
                          Pt =[100,20,60,40]
                          Knapsack(W,Wt,Pt)

                          main()


                          OUTPUT:-



                          -------------------------------------------------------------
                          Total Weight: 5
                          Weights: [3, 2, 4, 1]
                          Profit: [100, 20, 60, 40]
                          -------------------------------------------------------------
                          Rows: items and columns: weight.
                          [[ 0. 0. 0. 0. 0. 0.]
                          [ 0. 0. 0. 100. 100. 100.]
                          [ 0. 0. 20. 100. 100. 120.]
                          [ 0. 0. 20. 100. 100. 120.]
                          [ 0. 40. 40. 100. 140. 140.]]
                          -------------------------------------------------------------
                          Maximum Profit: 140.0
                          -------------------------------------------------------------
                          Items Added
                          [4, 1]




                          share








                          New contributor




                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          $endgroup$



                          Python Code for 1-0 Knapsack is:-



                          import numpy as np

                          def Knapsack(W, wt, profit):
                          print('-------------------------------------------------------------')
                          print('Total Weight: %s' %W)
                          print('Weights: %s' %wt)
                          print('Profit: %s' %profit)
                          mat = np.zeros((len(wt)+1, W+1))
                          for i in range(0,len(wt)+1):
                          for w in range(0,W+1):
                          if i==0 or w==0:
                          mat[i][w] = 0
                          elif wt[i-1]>w:
                          mat[i][w] = mat[i-1][w]
                          else:
                          mat[i][w] = max(mat[i-1][w],(profit[i-1]+mat[i-1][w-wt[i-1]]))

                          k=W
                          list =[]
                          for i in range(len(wt),-1,-1):
                          if mat[i, k] != mat[i - 1, k]:
                          k = k - wt[i-1]
                          if i!=0:
                          list.append(i)
                          print('-------------------------------------------------------------')
                          print('Rows: items and columns: weight.')
                          print(mat)
                          #i have added this below code to transpose if wanted
                          #transpose = zip(*mat)
                          #for row in transpose:
                          # print(row)
                          print('-------------------------------------------------------------')
                          print('Maximum Profit: %s' %mat[len(wt)][W])
                          print('-------------------------------------------------------------')
                          print('Items Added')
                          print(list)

                          def main():
                          W = 5
                          Wt =[3,2,4,1]
                          Pt =[100,20,60,40]
                          Knapsack(W,Wt,Pt)

                          main()


                          OUTPUT:-



                          -------------------------------------------------------------
                          Total Weight: 5
                          Weights: [3, 2, 4, 1]
                          Profit: [100, 20, 60, 40]
                          -------------------------------------------------------------
                          Rows: items and columns: weight.
                          [[ 0. 0. 0. 0. 0. 0.]
                          [ 0. 0. 0. 100. 100. 100.]
                          [ 0. 0. 20. 100. 100. 120.]
                          [ 0. 0. 20. 100. 100. 120.]
                          [ 0. 40. 40. 100. 140. 140.]]
                          -------------------------------------------------------------
                          Maximum Profit: 140.0
                          -------------------------------------------------------------
                          Items Added
                          [4, 1]





                          share








                          New contributor




                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.








                          share


                          share






                          New contributor




                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.









                          answered 5 mins ago









                          Abhishikt KadamAbhishikt Kadam

                          1




                          1




                          New contributor




                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.





                          New contributor





                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






                          Abhishikt Kadam is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f125374%2fsolution-to-the-0-1-knapsack-in-python%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

                              How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

                              Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...