Make depth first search for Knapsack non-recursive and more efficient. Solves all problems in reasonable time now.
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
3 10
|
|
||||||
45 5
|
|
||||||
48 8
|
|
||||||
35 3
|
|
||||||
@@ -3,6 +3,7 @@ from collections import namedtuple
|
|||||||
Result = namedtuple("Result", ['objective', 'is_optimal', 'xs'])
|
Result = namedtuple("Result", ['objective', 'is_optimal', 'xs'])
|
||||||
Item = namedtuple("Item", ['index', 'value', 'weight'])
|
Item = namedtuple("Item", ['index', 'value', 'weight'])
|
||||||
Knapsack = namedtuple("Knapsack", ['count', 'capacity', 'items'])
|
Knapsack = namedtuple("Knapsack", ['count', 'capacity', 'items'])
|
||||||
|
Node = namedtuple("Node", ['index', 'value', 'room', 'estimate', 'path'])
|
||||||
|
|
||||||
|
|
||||||
def solve_knapsack_greedy(knapsack):
|
def solve_knapsack_greedy(knapsack):
|
||||||
@@ -62,57 +63,69 @@ def solve_knapsack_dynamic(knapsack):
|
|||||||
|
|
||||||
|
|
||||||
def solve_knapsack_depth_first_search(knapsack):
|
def solve_knapsack_depth_first_search(knapsack):
|
||||||
knapsack.items.sort(key=lambda item: item.value / item.weight,
|
knapsack.items.sort(key=lambda item: item.value / float(item.weight),
|
||||||
reverse=True)
|
reverse=True)
|
||||||
num_items = len(knapsack.items)
|
|
||||||
result = {"objective": 0,
|
|
||||||
"path": []}
|
|
||||||
|
|
||||||
def get_max_value(from_index, capacity):
|
def get_estimate(current_value, current_index, remaining_capacity):
|
||||||
value = 0
|
estimated_value = current_value
|
||||||
for i in range(from_index, num_items):
|
for item in knapsack.items[current_index:]:
|
||||||
item = knapsack.items[i]
|
if item.weight <= remaining_capacity:
|
||||||
if item.weight <= capacity:
|
estimated_value += item.value
|
||||||
value += item.value
|
remaining_capacity -= item.weight
|
||||||
capacity -= item.weight
|
|
||||||
else:
|
else:
|
||||||
value += int((capacity / item.weight) * item.value)
|
v = int((remaining_capacity / float(item.weight)) * item.value)
|
||||||
break
|
estimated_value += v
|
||||||
return value
|
return estimated_value
|
||||||
|
return estimated_value
|
||||||
|
|
||||||
def search(index, capacity, value, path, result):
|
estimate = get_estimate(0, 0, knapsack.capacity)
|
||||||
if value > result["objective"]:
|
nodes = [Node(0, 0, knapsack.capacity, estimate, [])]
|
||||||
result["objective"] = value
|
num_items = len(knapsack.items)
|
||||||
result["path"] = list(path)
|
best_value = 0
|
||||||
|
best_path = []
|
||||||
|
|
||||||
if capacity <= 0:
|
while nodes:
|
||||||
return
|
current_node = nodes.pop()
|
||||||
|
current_index = current_node.index
|
||||||
|
|
||||||
if index == num_items:
|
if current_node.room < 0:
|
||||||
return
|
continue
|
||||||
|
|
||||||
# print("--- search")
|
if current_node.estimate < best_value:
|
||||||
# print("Index: {} capacity: {}, value: {}".format(index, capacity, value))
|
continue
|
||||||
# print("Path {}".format(path))
|
|
||||||
|
|
||||||
# Take current item.
|
if current_node.value > best_value:
|
||||||
max_value = get_max_value(index, capacity)
|
best_value = current_node.value
|
||||||
print(max_value)
|
best_path = list(current_node.path)
|
||||||
item = knapsack.items[index]
|
|
||||||
# print("max_value: {}".format(max_value))
|
|
||||||
max_value_not = get_max_value(index + 1, capacity)
|
|
||||||
# print("max_value_not: {}".format(max_value_not))
|
|
||||||
if item.weight <= capacity and value + max_value > result["objective"]:
|
|
||||||
path.append(1)
|
|
||||||
search(index + 1, capacity - item.weight,
|
|
||||||
value + item.value, path, result)
|
|
||||||
path.pop()
|
|
||||||
|
|
||||||
# Do not take current item.
|
if current_index == num_items:
|
||||||
if value + max_value_not > result["objective"]:
|
continue
|
||||||
path.append(0)
|
|
||||||
search(index + 1, capacity, value, path, result)
|
current_item = knapsack.items[current_index]
|
||||||
path.pop()
|
|
||||||
|
# Right child - do not take current_item
|
||||||
|
new_index = current_index + 1
|
||||||
|
new_value = current_node.value
|
||||||
|
new_room = current_node.room
|
||||||
|
new_estimate = get_estimate(new_value, new_index, new_room)
|
||||||
|
if new_estimate > best_value:
|
||||||
|
new_path = current_node.path + [0]
|
||||||
|
r = Node(new_index, new_value, new_room, new_estimate, new_path)
|
||||||
|
nodes.append(r)
|
||||||
|
|
||||||
|
# Left child - take current_item
|
||||||
|
new_index = current_index + 1
|
||||||
|
new_room = current_node.room - current_item.weight
|
||||||
|
if new_room >= 0:
|
||||||
|
new_value = current_node.value + current_item.value
|
||||||
|
new_estimate = get_estimate(new_value, new_index, new_room)
|
||||||
|
new_path = current_node.path + [1]
|
||||||
|
n = Node(new_index, new_value, new_room, new_estimate, new_path)
|
||||||
|
nodes.append(n)
|
||||||
|
|
||||||
|
# If we sort the items by estimate here it becomes
|
||||||
|
# best first search.
|
||||||
|
# nodes.sort(key=lambda node: node.estimate)
|
||||||
|
|
||||||
def correct_path(path):
|
def correct_path(path):
|
||||||
path = path + [0] * (num_items - len(path))
|
path = path + [0] * (num_items - len(path))
|
||||||
@@ -120,9 +133,7 @@ def solve_knapsack_depth_first_search(knapsack):
|
|||||||
path = [v[0] for v in sorted(values, key=lambda value: value[1].index)]
|
path = [v[0] for v in sorted(values, key=lambda value: value[1].index)]
|
||||||
return path
|
return path
|
||||||
|
|
||||||
search(0, knapsack.capacity, 0, [], result)
|
return Result(best_value, 0, correct_path(best_path))
|
||||||
|
|
||||||
return Result(result["objective"], 1, correct_path(result["path"]))
|
|
||||||
|
|
||||||
|
|
||||||
def input_data_to_knapsack(input_data):
|
def input_data_to_knapsack(input_data):
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/pypy
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import knapsack
|
import knapsack
|
||||||
|
|
||||||
|
|
||||||
def solve_it(input_data):
|
def solve_it(input_data):
|
||||||
# Modify this code to run your optimization algorithm
|
|
||||||
k = knapsack.input_data_to_knapsack(input_data)
|
k = knapsack.input_data_to_knapsack(input_data)
|
||||||
# r = knapsack.solve_knapsack_dynamic(k)
|
# r = knapsack.solve_knapsack_dynamic(k)
|
||||||
r = knapsack.solve_knapsack_depth_first_search(k)
|
r = knapsack.solve_knapsack_depth_first_search(k)
|
||||||
# r = knapsack.solve_knapsack_greedy(k)
|
|
||||||
return knapsack.result_to_output_data(r)
|
return knapsack.result_to_output_data(r)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user