最近遇见一个背包问题,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)