回溯法解决01背包问题

回溯法

问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。
只要是解可以描述成向量方式的,就可以使用回溯法,不断的扩张部分向量,向下深入的过程就是,从部分解到可行解的过程。
解必须满足多米诺性质:
可行解满足约束–>部分解满足约束
逆否为:部分解不满足约束–>可行解不满足约束

这样可以用来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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值