贪心算法原理:
每走一步,选出在这一步的最好选择。试图通过局部的最优(目光短浅)来实现整体的最优,但是从整体上看,又不是最优解。
题目:
一个背包,背包容量是M=140。有8个物品,物品不可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。 物品 A B C D E F G H
重量 25 30 6 50 40 10 25 3
价值 10 40 30 50 35 40 30 15
第一次尝试:
设计思路:用字典把物品代号及其重量~价值~单位重量的价值相互对应起来(此时用到zip函数:把两个列表里的数联合到一个字典里),再对物品的单价(我把物品的单价作为字典里的 “ 值 ”,把物品代号作为 “ 键 ”)进行大小排序,(此时又用到zip的另一个作用,默认对其对象里的第一个进行升序排序),排序后,我想通过for循环对其进行从后往前的遍历,即:当遍历到倒数第一个时,访问其对应的物品代号(即通过“值”访问“键”),在通过“键”(物品代号)去找出其对应重量与价值,判断是否满足其中重量是否能满足放进背包。再遍历倒数第二个,进行同样的操作,直到物品总重量超过背包容量。最后输出结果。(感觉这不是贪心算法了)
遇到的问题:程序复杂是次要问题,编写不出 “当遍历到倒数第一个时,访问其对应的物品代号(即通过“值”访问“键”),在通过“键”(物品代号)去找出其对应重量与价值,判断是否满足其中重量是否能满足放进背包。”才是主要问题。其中不知道怎样实现通过“值”访问“键”, 虽然写出来了相关代码,但是运行结果不是正确的。也就进行不了接下来的操作,所以放弃了。
下面是失利作品:
第二次尝试 :
设计思路:用字典把物品代号及其重量~价值~单位重量的价值相互对应起来(此时用到zip函数:把两个列表里的数联合到一个字典里),再对物品的单价(我把物品的单价作为字典里的 “ 值 ”,把物品代号作为 “ 键 ”)进行大小排序,经过多次尝试,决定对物品单价进行降序排列,降序排列后,反转键值,便于输出物品代号 来联系三个性质,最后形成的应是物品单价从大到小的的字典,然后从头遍历字典,筛选出满足条件的物品代号与价值总量。
遇到的问题:
1. 对物品单价字典进行从大到小的排序尝试很多次,不成功,总会出现错误,用的是sorted(iterable,key,reverse) ,主要是里面成分书写或多或少有出入,(其实到现在都没弄懂里面涉及的相关原理), 如下:
z=sorted(dict3.items(),key=lambda item:item[1],reverse=True)
其中lambda后面的item:item[1]不理解,不过reverse=True表示降序,当为False时,则为降序。
2.当对字典降序排列后,输出的不再是字典,而是
[('C', 5.0), ('H', 5.0), ('F', 4.0), ('B', 1.3333333333333333), ('G', 1.2), ('D', 1.0), ('E', 0.875), ('A', 0.4)]
{列表里包含元组,这又是一个棘手问题,于是又得想办法 把它转化为字典,(经过一段“艰辛和难熬”的百度,终于查出来了)
3.反转键值的格式不会,反转键值后,发现比原来少了数据,是因为变化前的值不唯一,(又难倒我了)
变化前:{'C': 5.0, 'H': 5.0, 'F': 4.0, 'B': 1.3333333333333333, 'G': 1.2, 'D': 1.0, 'E': 0.875, 'A': 0.4}
变化后:{5.0: 'H', 4.0: 'F', 1.3333333333333333: 'B', 1.2: 'G', 1.0: 'D', 0.875: 'E', 0.4: 'A'}
4.从头遍历新字典的表达方式中的变化量不会写 ,如下标了颜色的:
for value in new_dict.values():
print(value)
5.条件判断不起作用:我设置了重量和不超过背包容量,才执行价值的汇总,
for value in new_dict.values():
print(value)
ww=c+dict1.get(value)
if ww <= 140:
s += dict2.get(value)
print(value, s)
y1.append(value)
y2.append(s)
elif ww>140:
print("error")
print(y1,y2)
然而它还是一股脑儿全输了出来,
['H', 'F', 'B', 'G', 'D', 'E', 'A'] [15.0, 55.0, 95.0, 125.0, 175.0, 210.0, 220.0]
所以,只能在没超过值的范围内挑选。比如挑175.0以前的H,F,B,G.
第三次尝试:
设计思路:改进:不用反转键值,直接遍历字典里的键,得到物品代号。(虽然之前绕了很多,不过也绕来了很多知识点,知道有反转键值的操作)这样,就不会出现少数据的情况。
运行结果:
明显瑕疵:要从结果中挑出前四位才满足背包承载容量内,
条件判断不起作用
以下为完整代码:
w = [] # 储存物品重量
v = [] # 储存物品价值
d = [] # 储存物品单位重量的价值
y1 = []
y2=[]
keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
for i in range(8):
l = float(input("please input their weight:")) # 输入物品重量
w.append(l)
for i in range(8):
m = float(input("please input their value:")) # 输入物品价格
v.append(m)
for i in range(8): # 求解物品单位重量的价值
n = v[i] / w[i]
d.append(n)
print(w) # 连续输出便于观察程序的对错与进行
print(v)
print(d)
dict1 = dict(zip(keys, w)) # 用字典分别表示物品与其重量 价格 单价的对应关系
dict2 = dict(zip(keys, v))
dict3 = dict(zip(keys, d))
print(dict1) # 连续输出便于观察程序的对错与进行
print(dict2)
print(dict3)
z=sorted(dict3.items(),key=lambda item:item[1],reverse=True) #对字典降序排列
print(z)
x=dict(z) # 重新生成字典,
print(x)
s = 0 # 背包里的价值
c = 0 # 背包里的容量
for key in x.keys():
print(key)
ww=c+dict1.get(key)
if ww <= 140:
s += dict2.get(key)
print(key, s)
y1.append(key)
y2.append(s)
elif ww>140:
print("error")
print(y1,y2)