Python 向递归背包解决方案添加缓存阵列?

Python 向递归背包解决方案添加缓存阵列?,python,recursion,dynamic-programming,knapsack-problem,Python,Recursion,Dynamic Programming,Knapsack Problem,我熟悉这个问题的简单递归解决方案。然而,这个解决方案只是简单地给出了背包在给定重量约束的情况下可以存储的最大值。我想做的是添加某种形式的元数据缓存(即使用“一个热”数组[0,1,1]选择哪些项/未选择哪些项) 以下是我的尝试: 类解决方案: 定义初始化(自): self.array=[] def背包(自身、W、wt、val、n): 指数=n-1 如果n==0或W==0: 返回0 如果(wt[指数]>W): self.array.append(0) 选择=自我背包(W、wt、val、索引) 其他:

我熟悉这个问题的简单递归解决方案。然而,这个解决方案只是简单地给出了背包在给定重量约束的情况下可以存储的最大值。我想做的是添加某种形式的元数据缓存(即使用“一个热”数组
[0,1,1]
选择哪些项/未选择哪些项)

以下是我的尝试:

类解决方案:
定义初始化(自):
self.array=[]
def背包(自身、W、wt、val、n):
指数=n-1
如果n==0或W==0:
返回0
如果(wt[指数]>W):
self.array.append(0)
选择=自我背包(W、wt、val、索引)
其他:
选项A=val[index]+自助背包(W-wt[index],wt,val,index)
选项B=自背包(W、wt、val、索引)
如果选项A>选项B:
self.array.append(1)
选择=选项A
其他:
self.array.append(0)
选择=选项
打印(int(选项A>选项B))#告诉您所走的路径
返回选择
#测试上述功能
val=[60100120]
wt=[10,20,30]
W=50
n=len(val)
#印刷品(背包(W、wt、val、n))
s=解决方案()
s、 背包(W、wt、val、n)
>>>
1.
1.
1.
1.
1.
1.
220
s、 排列
>>>
[1, 1, 1, 1, 1, 1]
如您所见,
s.array
返回
[1,1,1,1,1]
,这告诉了我一些事情。(1) ,即使问题集中只有三个项目,背包方法对每个项目调用了两次,(2)这是因为每个项目都经过方法中的
else
语句,所以
option_A
option_B
都是为每个项目计算的(解释了为什么数组长度是6而不是3)

我不明白为什么每个递归循环中都附加了1。在最佳解决方案中,索引0处的项不会被选中。要回答此问题,请提供:

(A) 为什么当前的解决方案是这样的 (B) 如何重新构造代码,以便捕获一个热门的“接受或不接受”向量,表示给定的项目是否进入背包

谢谢大家!

(A) 为什么当前的解决方案是这样的

  • self.array
    是所有递归路径共享的实例属性。在一条路径或另一条路径上,每个项目都被获取,因此一个项目被附加到列表中
  • option\u A=val[index]…
    接受一个项目,但不将其附加到列表中
  • option\u B=self…..
    跳过一个项目,但不会在列表中附加零
  • 如果选项A>选项B:
    当您进行此比较时,您已经丢失了进行比较的信息-在分支中获取/丢弃的项目;
    • 在套件中,您只需附加一个1或零,而不管有多少项生成了这些值
    • 然后,1和0表示分支A(
      1
      )或分支B(
      0
      )在函数的当前实例中是否成功
(B) 如何重新构造代码,以便捕获一个热门的“接受或不接受”向量,表示给定的项目是否进入背包

在运行分析之后,很高兴知道您采取了哪些措施,我怀疑这就是您试图使用
self.array
所做的。您对OOP表示了兴趣:与其使用索引从列表中选择数字来跟踪数字列表,不如使用对象来表示这些项目。将对象保存在容器中,并使用容器的功能添加或删除其中的项/对象。考虑在选择一个容器之前如何使用容器。

  • 不要将函数放入类中
  • 将函数的签名更改为接受
    • 有效重量
    • 要考虑的物品容器
    • 一种容器,用于存放袋中当前的物品(当前袋)
  • 对具有值和权重属性的项使用collections.namedtuple或类。
  • 当一件物品被拿走时,将其添加到当前袋子中
  • 递归时
    • 如果沿着take路径,则将调用的返回值添加到当前sack
    • 从要考虑的项目列表中删除刚刚考虑的项目
    • 如果采用,则从可用重量参数中减去项目的重量
  • 在比较两个分支时,需要将当前sack中每个项目的值相加。
    • 返回具有最高值的sack
  • 请仔细考虑基本情况

将要考虑的项目设置为这样

import collections
Item = collections.namedtuple('Item',['wt','val'])
items = [Item(wght,value) for wght,value in zip(wt,val)]
value = sum(item.val for item in current_sack)
# or
import operator
val = operator.itemgetter('val')
wt = operator.itemgetter('wt')
value = sum(map(val,current_sack)
把这些值加起来

import collections
Item = collections.namedtuple('Item',['wt','val'])
items = [Item(wght,value) for wght,value in zip(wt,val)]
value = sum(item.val for item in current_sack)
# or
import operator
val = operator.itemgetter('val')
wt = operator.itemgetter('wt')
value = sum(map(val,current_sack)

您的解决方案通过为好奇者调试打印增强

class Solution:
    def __init__(self):
        self.array = []
        self.other_array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    
    def knapSack(self,W, wt, val, n,j=0):
        index = n-1 
        deep = f'''{' '*j*3}'''
        print(f'{deep}level {j}')
        print(f'{deep}{W} available: considering {wt[index]},{val[index]}, {n})')
        # minor change here but has no affect on the outcome0
        #if n == 0 or W == 0 :
        if n == 0:
            print(f'{deep}Base case found')
            return 0
        print(f'''{deep}{wt[index]} > {W} --> {wt[index] > W}''')
        if (wt[index] > W):
            print(f'{deep}too heavy')
            self.array.append(0)
            self.other_array[index] = 0
            choice = self.knapSack(W, wt, val, index,j+1) 

        else:
            print(f'{deep}Going down the option A hole')
            option_A = val[index] + self.knapSack( W-wt[index], wt, val, index,j+1)
            print(f'{deep}Going down the option B hole')
            option_B = self.knapSack(W, wt, val, index,j+1)
            print(f'{deep}option A:{option_A} option B:{option_B}')
            if option_A > option_B:
                print(f'{deep}option A wins')
                self.array.append(1)
                self.other_array[index] = 1
                choice = option_A
            else:             
                print(f'{deep}option B wins')
                self.array.append(0)
                self.other_array[index] = 0
                choice = option_B

        print(f'{deep}level {j} Returning value={choice}')
        print(f'{deep}---------------------------------------------')
        return choice

您是否进行过任何打印,或者您是否仔细查看了变量?确实有问题吗?是的,我在
print(int(option\u A>option\u B))
中添加了一行,它每次打印1(6次)。虽然我没有解决方案,但数组的问题是它是一个实例属性,由所有递归路径共享,并且每个项至少在其中一个路径中获取。你为什么选择这个设计?为什么要/需要一个
0/1
数组来指示是否采取了某些措施?选项B看起来从来没有赢过。对于递归调用,为什么您决定将完整列表与索引一起传递,而不是传递已删除项的列表?另外
if(wt[index]>W)
从不
True
@wwii感谢您的关注。最初的解决方案来自我尝试将其转换为OOP设计。然而,我可能在这个过程中破坏了一些功能。尽管如此,上面的代码生成的输出与