算法0-1背包问题:

参考博客:

http://blog.youkuaiyun.com/livelylittlefish/article/details/2186206

http://www.cnblogs.com/Anker/archive/2013/05/04/3059070.html

#coding=utf-8
def domatch(things):
    """
    把每个重量的最大值保存到weight_value_list
    weight_value_list:重量:保存在经过所有索引后的(重量,价值)键值对
    things:物品,由(重量,价值)构成
    """
    inthings=things[:]#内部使用的物品
    inthings.insert(0,(0,0))#插入初始物品(0,0)
    weight_value_list=dict()
    length=len(things) #列表长度
    oldresult=[(0,0,[])]#字典 索引:[(重量,价值,索引集合)]
    for index,(newweight,newvalue) in enumerate(inthings):
        if index>0:
            previndex=index-1
            newresult=[]#对当前索引的键值对初始化
            for weightindex,(weight,value,index_list) in enumerate(oldresult):#取出上一个索引的键值,然后再进行操作

                #weight_value_list[index].extend([(weight,value),(weight+newweight,value+newvalue)])
                newresult.append((weight,value,index_list))
                index_list2=index_list[:]
                index_list2.append(index)
                node2=(weight+newweight,value+newvalue,index_list2)
                newresult.append(node2)
            del oldresult[:]
            oldresult=newresult[:]
    weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
    alltuples=newresult
    for (weight,value,final_list) in  alltuples:
        if weight not in weight_value_dict:#如果重量没有在weight_value_dict中
            weight_value_dict[weight]=[value,final_list]
        elif weight_value_dict[weight][0]<value:#如果weight_value_dict中相对重量的价值小于value
            weight_value_dict[weight]=[value,final_list]
    return weight_value_dict



    #return weight_value_dict
def findmaxvalue(inweight,weight_value_dict):
    """
    查找最大价值
    """
    return weight_value_dict[inweight]#l输出的结果是[最大价值,索引列表]
if __name__=='__main__':
    weight_str='2 3 4 7'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='1 3 5 9 '
    vs=[int(item) for item in  value_str.split(' ') if item]
    things=zip(ws,vs)#(重量,价值)
    weight_value_dict=domatch(things)
    print findmaxvalue(10,weight_value_dict)
    #print things

结果:

但是发现有错误啊。。
但这段数据测试的时候
weight_str='2 2 6 5 4'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='6 3 5 4 6'

我取到的最大值是的4而不是的5.这就是问题所在了。

这是因为,我是在最后对每个重量取得最大价值,
按理而言,应该在遍历things的每一个元素的时候,就对oldresult做一下修理,使得对于每个重量一定取到小于或者等于该重量的价值的最大值。
最后代码如下:

#coding=utf-8
def domatch(things):
    """
    把每个重量的最大值保存到weight_value_list
    weight_value_list:重量:保存在经过所有索引后的(重量,价值)键值对
    things:物品,由(重量,价值)构成
    """
    inthings=things[:]#内部使用的物品
    inthings.insert(0,(0,0))#插入初始物品(0,0)
    weight_value_list=dict()
    length=len(things) #列表长度
    oldresult=[(0,0,[])]#字典 索引:[(重量,价值,索引集合)]
    for index,(newweight,newvalue) in enumerate(inthings):
        if index>0:

            newresult=[]#对当前索引的键值对初始化
            for weightindex,(weight,value,index_list) in enumerate(oldresult):#取出上一个索引的键值,然后再进行操作

                #weight_value_list[index].extend([(weight,value),(weight+newweight,value+newvalue)])
                newresult.append((weight,value,index_list))
                index_list2=index_list[:]
                index_list2.append(index)
                node2=(weight+newweight,value+newvalue,index_list2)
                newresult.append(node2)
            del oldresult[:]
            oldresult=newresult[:]
            #对oldresult作整理,使得对于每个重量的价值取到的一定是小于或者等于该重量的最大价值
            weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
            alltuples=newresult
            for (fweight,fvalue,final_list) in  alltuples:
                #如果重量没有在weight_value_dict中
                if fweight not in weight_value_dict:
                    weight_value_dict[fweight]=(fvalue,final_list)
                    #如果weight_value_dict中相对重量的价值小于value
                elif weight_value_dict[fweight][0]<fvalue:
                    weight_value_dict[fweight]=(fvalue,final_list)
            oldresult=[]
            for dweight,(dvalue,dlist) in weight_value_dict.iteritems():
                oldresult.append((dweight,dvalue,dlist))
            oldresult.sort( key=lambda x:x[0])#按照重量排序
            for sortedindex,(comweight,comvalue,comli) in enumerate(oldresult):
                if sortedindex>0:
                    previndex=sortedindex-1
                    if oldresult[previndex][1]>comvalue:
                        oldresult[sortedindex]=(comweight,)+tuple(oldresult[previndex][1:])

    weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
    alltuples=newresult
    for (weight,value,final_list) in  alltuples:
        if weight not in weight_value_dict:#如果重量没有在weight_value_dict中
            weight_value_dict[weight]=[value,final_list]
        elif weight_value_dict[weight][0]<value:#如果weight_value_dict中相对重量的价值小于value
            weight_value_dict[weight]=[value,final_list]
    return weight_value_dict



    #return weight_value_dict
def findmaxvalue(inweight,weight_value_dict):
    """
    查找最大价值
    """

    return weight_value_dict[inweight]#l输出的结果是[最大价值,索引列表]
if __name__=='__main__':
    weight_str='12 16 24 7 29 32 5 43 31 1'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='11 16 15 9 24 25 3 32 41 7'
    vs=[int(item) for item in  value_str.split(' ') if item]
    things=zip(ws,vs)#(重量,价值)
    weight_value_dict=domatch(things)
    print findmaxvalue(105,weight_value_dict)
    #print things

输出结果是:

但是我在用递归法写的时候却出现了问题:

#coding=utf-8
def findmaxvalue(weight,things):
    inthings=things[:]
    inthings.insert(0,(0,0))
    lenofthings=len(inthings)
    return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known=dict()
def findmaxvaluebylen(weight,inthings,index,maxindex):
    """
    weight:要求得最大价值时的重量
    inthings:已经被处理过的列表
    index:在遍历inthings时的索引
    maxindex:inthings的最大索引
    """
    if index in known:
        return known[index]
    else:
        if index==0:
            reobject=(weight,0,[])#重量,价值,索引列表
            known[index]=reobject
            return reobject
        else:
            nowweight,nowvalue=inthings[index]
            if nowweight>weight:
                reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
                known[index]=reobject
                return reobject
            else:
                reobject1=findmaxvaluebylen(weight,inthings,index-1,maxindex)#当前节点不包含在结果中
                newweight=weight-nowweight
                reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)#当前节点包含在结果里
                ele_list=reobject2[2][:]
                ele_list.append(index)
                reobject2=(weight,reobject2[1]+nowvalue,ele_list)
                reobject=reobject1
                if reobject1[1]<reobject2[1]:
                    reobject=reobject2
                known[index]=reobject
                return reobject
if __name__=='__main__':
    weight_str='12 16 24 7 29 32 5 43 31 1'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='11 16 15 9 24 25 3 32 41 7'

    vs=[int(item) for item in  value_str.split(' ') if item]
    things=zip(ws,vs)#(重量,价值)
    things.sort()
    print findmaxvalue(105,things)
    #print things

结果却是这个样子:


跟之前的对不上啊,这是怎么回事啊。。为什么会这个样子呢。。真坑啊。

应该是我子结构错了,改下子结构:

结果如下:

#coding=utf-8
def findmaxvalue(weight,things):
    inthings=things[:]
    inthings.insert(0,(0,0))
    lenofthings=len(inthings)
    return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known={0:{0:(0,[])}}
def findmaxvaluebylen(weight,inthings,index,maxindex):
    """
    weight:要求得最大价值时的重量
    inthings:已经被处理过的列表
    index:在遍历inthings时的索引
    maxindex:inthings的最大索引
    """
    if index in known:
        tempdict=known[index]
        if weight in tempdict:
            return tempdict[weight]
    if index==0:
        reobject=(0,[])
        known[index][weight]=reobject
        return reobject
    nowweight,nowvalue=inthings[index]
    reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
    #发现在index==3 and weight==5的时候,reobject=None
    if nowweight>weight:
        fixdictbyobject(known,index,weight,reobject)
        known[index][weight]=reobject

        return reobject
    else:
        newweight=weight-nowweight
        reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)
        ele_list=reobject2[1][:]
        ele_list.append(index)
        reobject2=(reobject2[0]+nowvalue,ele_list)
        if reobject[0]<reobject2[0]:
            reobject=reobject2
        fixdictbyobject(known,index,weight,reobject)
        known[index][weight]=reobject
        return reobject
def fixdictbyobject(known_dict,index,comweight,reobject):
    """
    整理 known_dict[index]
    使得所有重量大于comweight的价值都大于或者等于reobject的价值,
    """
    if  index not in known_dict:
        known_dict[index]=dict()
        return
    else:
        for tempweight,(tempvalue,templist) in known_dict[index].iteritems():
            if tempweight>comweight and tempvalue<reobject[0]:
                known_dict[index][tempweight]=reobject[:]
        return
if __name__=='__main__':
    weight_str='12 16 24 7 29 32 5 43 31 1'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='11 16 15 9 24 25 3 32 41 7'

    vs=[int(item) for item in  value_str.split(' ') if item]
    things=zip(ws,vs)#(重量,价值)
    things.sort()
    print findmaxvalue(105,things)
    #print things
但是结果还是有问题啊

最大价值没错,但是索引列表错了啊。这是怎么会事呢

这个为什么是[1,2,3,4,5,8,9]呢,蛋疼啊。
知道为什么会这个样子了。。原来是我对things.sort()进行了排序。。。注销掉那一句就行了。
最终代码为:

#coding=utf-8
def findmaxvalue(weight,things):
    inthings=things[:]
    inthings.insert(0,(0,0))
    lenofthings=len(inthings)
    return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known={0:{0:(0,[])}}
def findmaxvaluebylen(weight,inthings,index,maxindex):
    """
    weight:要求得最大价值时的重量
    inthings:已经被处理过的列表
    index:在遍历inthings时的索引
    maxindex:inthings的最大索引
    """
    if index in known:
        tempdict=known[index]
        if weight in tempdict:
            return tempdict[weight]
    if index==0:
        reobject=(0,[])
        known[index][weight]=reobject
        return reobject
    nowweight,nowvalue=inthings[index]
    reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
    if nowweight>weight:
        fixdictbyobject(known,index,weight,reobject)
        known[index][weight]=reobject

        return reobject
    else:
        newweight=weight-nowweight
        reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)
        ele_list=reobject2[1][:]
        ele_list.append(index)
        reobject2=(reobject2[0]+nowvalue,ele_list)
        if reobject[0]<reobject2[0]:
            reobject=reobject2
        fixdictbyobject(known,index,weight,reobject)
        known[index][weight]=reobject
        return reobject
def fixdictbyobject(known_dict,index,comweight,reobject):
    """
    整理 known_dict[index]
    使得所有重量大于comweight的价值都大于或者等于reobject的价值,
    """
    if  index not in known_dict:
        known_dict[index]=dict()
        return
    else:
        for tempweight,(tempvalue,templist) in known_dict[index].iteritems():
            if tempweight>comweight and tempvalue<reobject[0]:
                known_dict[index][tempweight]=reobject[:]
        return
if __name__=='__main__':
    weight_str='12 16 24 7 29 32 5 43 31 1'
    ws=[ int(item) for item in weight_str .split(' ') if item]
    value_str='11 16 15 9 24 25 3 32 41 7'

    vs=[int(item) for item in  value_str.split(' ') if item]
    things=zip(ws,vs)#(重量,价值)
    #things.sort()
    print findmaxvalue(105,things)
    #print things

运行的结果为:

终于把0-1背包问题解决了,。。弄了两天了。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值