Python背包问题,无重复,无分割,非贪婪求解

最近遇见一个背包问题,scores = [15,10,9,5]和weitghts = [1,5,3,4]列表长度一致,如果背包重量为8,则最优解是29,weitghts中1+3+4的重量对应的分数和(15+9+5)=29,其实不难,但是大部分推荐贪婪算法,但是好多贪婪算法,个别重量可重复或者可分割,考虑了半天,做出来了一个类似穷举法的方法求最优解,其实还有优化的地方,例如再次输入,如果scores和weitghts没变过,单独求背包重量最优解,我的final_price_list只需要保存最初那次字典即可等等。

import itertools as it
scores = [15,10,9,5]
weitghts = [1,5,3,4]

#根把weight做成一个字典
weight_index_dict1 = dict(enumerate(weitghts))
#再把字典键值对反转,这样通过key可以对应scores的下标
weight_index_dict2 = {k:v for v,k in weight_index_dict1.items()}

dict_value = {}
price_list = []

#迭代所有组合,

def iterall(weitghts:list,cap = 8):
    for i in range(1,len(weitghts)+1):
        iternum(weitghts,i)
    get_max(cap)

#迭代某个组合,例如num=3,得到(1,5,3)、(1,5,4)、(5,3,4)组合

def iternum(weitghts:list,num:int):
    for item in it.combinations(weitghts,num):
        total_weight = 0
        temp_price = 0
        for index,value in enumerate(item):
            total_weight += value
            temp_price += get_index(value)
        add_dict(total_weight,temp_price)

#这里做了一个反字典,通过weights的值,得到对应的下标,进而得到scores对应的分数

def get_index(key):
    index = weight_index_dict2[key]
    return scores[index]

#做了一个字典集合,把所有组合放进一个字典,例如重量8,可以1+3+4也可以5+3,分数分别是15+9+4和10+9,但是如果键值存在(8),则判断,如果key大于原来的key,才会覆盖,如果是新key,则添加

def add_dict(key,value):
    if key in dict_value:
        if value > dict_value[key]:
                dict_value[key] = value
    else:
        dict_value.update({key:value})

#dict_value已经把所有的重量组合以及对应的分数拿到,即重量1,最优就是15分,{1: 15, 5: 20, 3: 9, 4: 24, 6: 25, 8: 29, 9: 34, 7: 14, 10: 30, 12: 24, 13: 39}

#这里有个问题,如果背包是3 ,则最优解反而是装weights[0],背包装到1则足够得到15分,而不是3

def get_max(cap:int):
    final_price_list = []
    for k,v in dict_value.items():
    if k<=cap:
            final_price_list.append(v)
    print(final_price_list)
    max_price = max(final_price_list)
    print(max_price)
    return max_price

if __name__ == '__main__':
    iterall(weitghts,3)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值