import logging from dataclasses import dataclass from tabulate import tabulate logging.basicConfig( level=logging.DEBUG, format="%(asctime)s %(levelname)s\n\r%(message)s", datefmt="%H:%M:%S", ) logger = logging.getLogger(__name__) @dataclass class Item: name: str priority: int weight: int def dynamic(items, n): # create table and zero fill it (required for calculations) table = [[0 for _ in range(W + 1)] for _ in range(n + 1)] # calculate all possible max values for items in knapsack for i in range(1, n + 1): for w in range(1, W + 1): if items[i - 1].weight <= w: table[i][w] = max( items[i - 1].priority + table[i - 1][w - items[i - 1].weight], table[i - 1][w], ) else: table[i][w] = table[i - 1][w] format_and_print(table) return get_items_in_knapsack(table[-1][-1], items, n, table) def format_and_print(table): # enumerate first row (headings) + label each row in column0 for i, row in enumerate(table): if i == 0: continue row[0] = items[i - 1].name table[0] = [None, *[i for i in range(1, W + 1)]] # print tabularised 2D array logger.info([item.name for item in items]) logger.info(tabulate(table, tablefmt="pretty")) def get_items_in_knapsack(highest_value, items, n, table): in_knapsack = [] w = W res = highest_value for i in range(n, 0, -1): if res <= 0: break if res == table[i - 1][w]: continue else: in_knapsack.append(items[i - 1].name) res = res - items[i - 1].priority w = w - items[i - 1].weight return in_knapsack items = [ Item("Water", 10, 3), Item("Book", 3, 1), Item("Food", 9, 2), Item("Jacket", 5, 2), Item("Camera", 6, 1), ] W = 6 in_knapsack = dynamic(items, len(items)) print(f"Knapsack contains: {in_knapsack}")