对于在线课程,我尝试分别解决knapsack problem:给定n
项和数组v
及w
的值和权重,找到具有最大值的项目组合,但要遵守总权重小于给定阈值W
的约束。
我使用A(i, x, v, w)
项和总权重约束i
定义子问题x
的解决方案;因此,问题是计算A(n, W, v, w)
。我尝试过以下方法:
import sys
sys.setrecursionlimit(3000)
def memoize(f):
memo = {}
def helper(i, x, *args, **kwargs):
if (i, x) not in memo:
memo[(i, x)] = f(i, x, *args, **kwargs)
return memo[(i, x)]
return helper
@memoize
def A(i, x, v, w):
if i == 0:
return 0
if x >= w[i-1]:
return max(A(i-1, x, v, w), A(i-1, x-w[i-1], v, w) + v[i-1])
else:
return A(i-1, x, v, w)
如果我在一个简单的测试用例上运行它,它可以工作:
import pytest
@pytest.fixture
def data_simple():
W = 6
n = 4
v = [3, 2, 4, 4]
w = [4, 3, 2, 3]
return W, n, v, w
def test_A(data_simple):
W, n, v, w = data_simple
assert A(n, W, v, w) == 8
if __name__ == "__main__":
pytest.main([__file__, "-s"])
在这种情况下,最大值是通过取最后两个项目获得的,每个项目的值为4。
但是,对于实际问题,我们需要使用从knapsack_big.txt获得的更大输入数据集,其中W
= 2,000,000且n
= 2,000。
我试图按如下方式运行:
def readfile(file):
with open(file) as f:
first_line = f.readline().strip()
W, n = tuple(map(int, first_line.split()))
data = [tuple(map(int, line.split())) for line in f.read().splitlines()]
v, w = zip(*data)
assert len(v) == n
return W, n, v, w
@pytest.fixture
def data_big():
return readfile('knapsack_big.txt')
def test_big(data_big):
W, n, v, w = data_big
optimal_value = A(n, W, v, w)
然而,当我尝试运行时,我得到RecursionError
:
def helper(i, x, *args, **kwargs):
if (i, x) not in memo:
> memo[(i, x)] = f(i, x, *args, **kwargs)
E RecursionError: maximum recursion depth exceeded
我不明白这一点:如果每次调用函数A
,它的值{}为i
,i
的最大值为{ {1}},那么3000的递归深度(在开头设置)是否足够?
(我怀疑可能是这样的情况是每次调用2000
时都会调用memoize
函数包装器,所以每次都会创建一个空的A
字典而不是填写字典。我基于http://www.python-course.eu/python3_memoization.php的示例,但也许我应该尝试https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize处的一些实现?)
答案 0 :(得分:2)
它属于Maximum recursion depth exceeded
,因为每次调用函数A
helper
时,也会调用函数,所以实际上每次递减i
时都会有两次递归调用。我尝试通过在函数helper
中实现memoization来删除对A
的调用,并且它有效:
memo = {}
def A2(i, x, v, w):
global memo
if i == 0:
return 0
if (i, x) not in memo:
if x >= w[i - 1]:
memo[(i, x)] = max(A2(i - 1, x, v, w),
A2(i - 1, x - w[i - 1], v, w) + v[i - 1])
else:
memo[(i, x)] = A2(i - 1, x, v, w)
return memo[(i, x)]
输出:
4243395