限界分支法:队列实现方式
前面已经介绍过限界分支法大部分是基于广度优先搜索,广度优先搜索一般借助于队列实现,剪枝的情况可以借助于优先级队列。
实现如下:
#%%
class FIFO_01_Pack:
def __init__(self,N,V,C,W):
self.num =N
self.Volume = V
self.Cost = C
self.Value = W
self.BestValue = 0
#用于存放活结点,便于理解,把根结点,以及第0层结束标志-1放进去
# 结点包括2个属性:当前空间大小,当前的价值大小
self.queue = [[0,0],[-1,-1],]
# 实现时叶子结点不加入到活结点列表,当属于叶子结点时,增加对结果的处理
def enQueen(self,pair,depth):
if depth == self.num -1:
CurValue = pair[1]
if CurValue > self.BestValue:
self.BestValue = CurValue
else:
self.queue.append(pair)
def pack_01(self):
# selected = [0]*self.num
# 首先取出根结点
depth = 0
pair = self.queue.pop(0)
CurCost = pair[0]
CurValue = pair[1]
while True:
# 判断左结点能否加入到队列,能的话,把当前空间和当前价值放入队列
if CurCost + self.Cost[depth] < self.Volume:
self.enQueen([CurCost + self.Cost[depth],CurValue + self.Value[depth]],depth)
# 右结点总是可以加入队列的,因为没有约束条件的限制
self.enQueen([CurCost,CurValue],depth)
# 然后弹出下一个结点
pair = self.queue.pop(0)
CurCost = pair[0]
CurValue = pair[1]
# 当同一层处理完毕时,先判断是否能够输出结果,判断的标准是队列是否为空,
# 这时下一层的所有结点已经加入了队列,这时需要把下一层
# 增加一个结尾-1便于判断,然后进入下一层,弹出下一个结点
if CurCost == -1:
if not self.queue:
return self.BestValue
self.enQueen([-1,-1],depth)
depth += 1
pair = self.queue.pop(0)
CurCost = pair[0]
CurValue = pair[1]
def print_Result(self):
print(self.pack_01())
Baseline对比及结果输出:
class pack_01_back_test:
def __init__(self,N,V,C,W):
self.num =N
self.V = V
self.C = C
self.W = W
self.BestResult = [False]*N
self.Selected = [False]*N
self.BestValue = 0
self.CurCost = 0
self.CurValue = 0
def pack_01_back_tracking(self,depth):
if depth > self.num-1:
if self.CurValue > self.BestValue:
self.BestValue = self.CurValue
self.BestResult[:] = self.Selected[:]
else:
if self.CurCost + self.C[depth] <= self.V:
self.Selected[depth] = True
self.CurCost += self.C[depth]
self.CurValue += self.W[depth]
# next
self.pack_01_back_tracking(depth+1)
# undo
self.CurCost -= self.C[depth]
self.CurValue -= self.W[depth]
self.Selected[depth] = False
self.pack_01_back_tracking(depth+1)
def print_Result(self):
self.pack_01_back_tracking(0)
print(self.BestResult)
print(self.BestValue)
#%%
N = 8
V = 30
C = [11,2,3,9,13,6,15,7,19]
W = [5.0,2.0,5.0,7.0,5.0,11.0,6.0,14.0]
pack_01_back_test(N,V,C,W).print_Result()
FIFO_01_Pack(N,V,C,W).print_Result()
[False, True, True, True, False, True, False, True]
39.0
39.0
追踪解
追踪解,上述实现的情况下,解都在最后一层,根本不知道之前的路径是怎样的,广度优先搜索,同一个纬度,假如不加指标判断的话,根本不知道最优解是选择的哪一个,所以需要同一个纬度的每一个结点,记住他之前的路径,才能在最优解的时候之前是怎么走过来的,每一个结点用一个数组记录路径,这样实现的感觉消耗有点大啊,通常看见是采用链表方式