美文网首页数据结构和算法分析
分支界限法(Branch and Bound)-问题1: 0/

分支界限法(Branch and Bound)-问题1: 0/

作者: WAY_elegant | 来源:发表于2019-02-16 20:53 被阅读2次

    本范例主要是通过分支界限法解决著名的0/1背包客问题


    问题描述:
    N=4件商品,记为A,B,C,D,E。每件商品的重量和价值分别为w[i]v[i];
    其中w=[1.98,2,5,3.4], v=[100,40,95,50]
    现在有一个背包,可以容纳的最大重量为W=10
    问该背包可以包含的最大价值是多少?

    基本思路:
    本问题是一个典型的排列组合问题,只要能满足总重量小于背包的容量的所有组合中,找到那个价值最大的组合;

    每一件商品都有2种选择,要么包含该商品,要么不包含该商品
    因此总共有2^N种组合方式。当N很大时,如果尝试每一种组合方式,将会使得计算量变得非常大。如下图所示

    上图中每一个小圆圈都代表一个节点,对于每一个小节点,都拥有两个分支,两种选择,即包不包含某一个商品,这既是分支界限法种分支的由来。而界限是指我们做每一个选择时,我们先提前预估一下加入做了该选择,可能出现的最优或最差情况,即所谓的上界和下界

    比如我们从零开始,我们算一下最大价值是多少?按照贪婪算法思想,我们商品已由单位重量价值进行了从大到小的排列

    那么开始最大可能价值就是A,B,C全部包含,D商品部分包含V_{max} =100+40+95+(10-1.98-2-5) *50/3.4 = 250, 由于可以包含部分商品,因此本价值提供了可能最大价值的上限。

    假如包含商品A,则上限还是250,假如不包含商品A,则上限计算应是B,C的全部价值加D部分价值,应该是
    40+95+(10-2-5)*50/3.4=179.12

    分支界限法的思想就是不断选择那个预测值最大的路,像上述包含商品A预测值大于不包含商品A的情况,因此,我们暂时选择包含商品A,下一步就可以考虑是否包含商品B,计算方法类似

    更换路线条件:
    按照上述方法就为沿着一条路线不断前进且在岔路口选择是否包含某一商品提供了一种判断方法,那么什么情况得更换线路呢?

    1. 重量超标的情况,本例中,假如每一条路线重量超过了10,则该路走不通了,必须切换到当前预测价值最大的那条线路。
    2. 预测值下降严重,已经小于另一条线路上的预测值,这是应更换到那条预测值大的线路上,也就是说时刻走预测值最大的那条线路

    结束条件:

    • 每一件商品都考虑到了,如何此时还是最优的情况,那么这条线路就一定是最优的情况,如本例中就是包含商品A,B,C,不包含商品D,最大价值是235


    python代码

    """
    Created on Mon Jan  7 21:57:42 2019
    
    @author: WAY
    """
    
    from copy import copy,deepcopy
    class Item:
        def __init__(self,w,v):
            self.w = w
            self.v = v
            self.r = v/w
        def __lt__(self,other):
            return self.r<other.r
    
    class Node:
        def __init__(self):
            self.layer = -1
            self.info=[]
            self.optimum_value = -1
            self.total_weight=0
        def __lt__(self,other):
            return self.optimum_value<other.optimum_value
    
    
    class Knapsack:
        def __init__(self,N,maxweight):
            self.N=N
            self.items = []
            self.max_weight = maxweight
            self.max_value = 0
            self.quene = []
        def add_item(self,item):
            self.items.append(item)
        def sort_item(self):
            self.items.sort()
            self.items.reverse()
        def calculate_matrix_value(self,node):
            weight = 0
            value = 0
            for i in node.info:
                weight += i.w
                value += i.v
            if weight>self.max_weight:
                node.optimum_value = -1
                return
            node.total_weight=weight
            for j in range(node.layer+1,self.N):
                if weight + self.items[j].w <= self.max_weight:
                    weight += self.items[j].w
                    value += self.items[j].v
                else:
                    value += self.items[j].r*(self.max_weight-weight)
                    break
            node.optimum_value = value
        def knapsack(self):
            node = Node()
            self.calculate_matrix_value(node)
            self.max_value = node.optimum_value
            self.quene.append(node)
            panduan = 0
            while self.quene:
                if panduan == 0:
                    node = self.quene.pop()
                panduan=1
                node_L = deepcopy(node)
                node_L.layer += 1
                node_L.info.append(self.items[node_L.layer])
                self.calculate_matrix_value(node_L)
                if node_L.optimum_value>0  and node_L.optimum_value <=self.max_value:
                    self.quene.append(node_L)
                
                node_R = deepcopy(node)
                node_R.layer += 1
                self.calculate_matrix_value(node_R)
                if node_R.optimum_value>0  and node_R.optimum_value <=self.max_value:
                    self.quene.append(node_R)
                self.quene.sort()
                node = self.quene.pop()
                
                if node.layer == 3:
                    break
            return node
    
    def main():
        item1 = Item(2,40)
        item2 = Item(3.14,50)
        item3 = Item(1.98,100)
        item4 = Item(5,95)
        k = Knapsack(4,10)
        k.add_item(item1)
        k.add_item(item2)
        k.add_item(item3)
        k.add_item(item4)
        k.sort_item()
        nn = k.knapsack()
        print(nn.optimum_value)
        print(nn.total_weight)
        for i in nn.info:
            print(i.w)
    
    
    if __name__ == "__main__":
        main()
    

    相关文章

      网友评论

        本文标题:分支界限法(Branch and Bound)-问题1: 0/

        本文链接:https://www.haomeiwen.com/subject/mfjveqtx.html