回溯法
问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。
只要是解可以描述成向量方式的,就可以使用回溯法,不断的扩张部分向量,向下深入的过程就是,从部分解到可行解的过程。
解必须满足多米诺性质:
可行解满足约束–>部分解满足约束
逆否为:部分解不满足约束–>可行解不满足约束
这样可以用来pruning。
最简单的回溯,解空间为二叉树,又叫子集树
递归方式实现的框架如下:
void backtrack(int t){
if(t > n) output(x);
else{
for(int i = f(n,t); i <= g(n,t);i++){
x[t] = h(i);
if(constraint(t) && bound(t)) backtrack(t+1);
}
}
}
实现代码如下:
def pack_01_back(N,V,C,W):
BestResult = [0]*N
x = [0]*N
BestValue = [0]
CurCost = [0]
CurValue = [0]
def pack_01_back_tracking(depth):
# 递归出口
if depth > N-1:
if CurValue[0] > BestValue[0]:
BestValue[0] = CurValue[0]
# x为可行解,在叶子处把可行解记录下来
BestResult[:] = x[:]
print BestResult
print BestValue
# 注意else的含义
else:
for i in range(2):
x[depth] = i
if i == 0:
pack_01_back_tracking(depth+1)
else:
if CurCost[0] + C[depth] <= V:
CurCost[0] += C[depth]
CurValue[0] += W[depth]
pack_01_back_tracking(depth+1)
# 回溯时的处理,就是往上回溯时,要把吃进去的吐出来
CurCost[0] -= C[depth]
CurValue[0] -= W[depth]
pack_01_back_tracking(0)
return BestResult,BestValue
迭代方式实现
顺序执行流程图如下
代码如下
注意不剪枝,回溯是在最底部,回溯到最后放入的那个物品
#%%
def pack_01_back_iteration2(N,V,C,W):
depth = 0
BestResult = [False]*N
Selected = [False]*(N)
BestValue = 0
CurCost = 0
CurValue = 0
while True:
if depth < N:
if CurCost + C[depth] <= V:
Selected[depth] = True
CurCost += C[depth]
CurValue += W[depth]
# 回溯是处于底部
else:
if CurValue > BestValue:
BestValue = CurValue
BestResult[:] = Selected[:]
# 到底部时,已经超了一个
depth -=1
while depth >= 0 and not Selected[depth]:
depth -=1
# 回溯到root退出
if depth < 0:
break
# undo
else:
Selected[depth] =False
CurCost -= C[depth]
CurValue -= W[depth]
depth +=1
return BestResult,BestValue
#%%
def pack_01_back_iteration(N,V,C,W):
depth = 0
BestResult = [False]*N
Selected = [False]*(N)
BestValue = 0
CurCost = 0
CurValue = 0
while depth >= 0:
while depth < N:
if CurCost + C[depth] <= V:
Selected[depth] = True
CurCost += C[depth]
CurValue += W[depth]
depth +=1
else:
Selected[depth] = False
depth +=1
if CurValue > BestValue:
BestValue = CurValue
BestResult[:] = Selected[:N]
depth -=1
while depth > 0 and Selected[depth] == 0:
depth -=1
if Selected[depth] ==1:
Selected[depth] =False
CurCost -= C[depth]
CurValue -= W[depth]
depth +=1
if depth == 0:
break
return BestResult,BestValue
运行结果:
#%%
N = 8
V = 30
C = [11,2,3,9,13,6,15,7,19]
W = [5,2,5,7,5,11,6,14]
print pack_01_back(N,V,C,W)
print pack_01_back_iteration(N,V,C,W)
print pack_01_back_iteration2(N,V,C,W)
runfile('/root/test/back_tracking.py', wdir='/root/test')
([False, True, True, True, False, True, False, True], [39])
([False, True, True, True, False, True, False, True], 39)
([False, True, True, True, False, True, False, True], 39)