#!/usr/bin/env python # coding: utf-8 # This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges). # # Challenge Notebook # ## Problem: Given a knapsack with a total weight capacity and a list of items with weight w(i) and value v(i), determine which items to select to maximize total value. # # * [Constraints](#Constraints) # * [Test Cases](#Test-Cases) # * [Algorithm](#Algorithm) # * [Code](#Code) # * [Unit Test](#Unit-Test) # * [Solution Notebook](#Solution-Notebook) # ## Constraints # # * Can we replace the items once they are placed in the knapsack? # * No, this is the 0/1 knapsack problem # * Can we split an item? # * No # * Can we get an input item with weight of 0 or value of 0? # * No # * Can we assume the inputs are valid? # * No # * Are the inputs in sorted order by val/weight? # * Yes, if not we'd need to sort them first # * Can we assume this fits memory? # * Yes # ## Test Cases # # * items or total weight is None -> Exception # * items or total weight is 0 -> 0 # * General case # #
# total_weight = 8
# items
#   v | w
#   0 | 0
# a 2 | 2
# b 4 | 2
# c 6 | 4
# d 9 | 5
# 
# max value = 13
# items
#   v | w
# b 4 | 2
# d 9 | 5 
# 
# ## Algorithm # # Refer to the [Solution Notebook](http://nbviewer.jupyter.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/knapsack_01/knapsack_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start. # ## Code # In[ ]: class Item(object): def __init__(self, label, value, weight): self.label = label self.value = value self.weight = weight def __repr__(self): return self.label + ' v:' + str(self.value) + ' w:' + str(self.weight) # In[ ]: class Knapsack(object): def fill_knapsack(self, input_items, total_weight): # TODO: Implement me pass # ## Unit Test # **The following unit test is expected to fail until you solve the challenge.** # In[ ]: # %load test_knapsack.py import unittest class TestKnapsack(unittest.TestCase): def test_knapsack_bottom_up(self): knapsack = Knapsack() self.assertRaises(TypeError, knapsack.fill_knapsack, None, None) self.assertEqual(knapsack.fill_knapsack(0, 0), 0) items = [] items.append(Item(label='a', value=2, weight=2)) items.append(Item(label='b', value=4, weight=2)) items.append(Item(label='c', value=6, weight=4)) items.append(Item(label='d', value=9, weight=5)) total_weight = 8 expected_value = 13 results = knapsack.fill_knapsack(items, total_weight) self.assertEqual(results[0].label, 'd') self.assertEqual(results[1].label, 'b') total_value = 0 for item in results: total_value += item.value self.assertEqual(total_value, expected_value) print('Success: test_knapsack_bottom_up') def test_knapsack_top_down(self): knapsack = KnapsackTopDown() self.assertRaises(TypeError, knapsack.fill_knapsack, None, None) self.assertEqual(knapsack.fill_knapsack(0, 0), 0) items = [] items.append(Item(label='a', value=2, weight=2)) items.append(Item(label='b', value=4, weight=2)) items.append(Item(label='c', value=6, weight=4)) items.append(Item(label='d', value=9, weight=5)) total_weight = 8 expected_value = 13 self.assertEqual(knapsack.fill_knapsack(items, total_weight), expected_value) print('Success: test_knapsack_top_down') def main(): test = TestKnapsack() test.test_knapsack_bottom_up() test.test_knapsack_top_down() if __name__ == '__main__': main() # ## Solution Notebook # # Review the [Solution Notebook]() for a discussion on algorithms and code solutions.