01背包问题的代码实现与算法比较
01背包问题
关于01背包问题的具体描述可以参考0-1背包问题的动态规划算法-by Liu言杂记
事实上,我今天的内容就是对上述文章的部分代码实现及算法比较。
贪婪算法与其无法得到最优解的证明
我将这个问题的贪婪算法实现的分为三种:
- 价值-贪婪
- 时间贪婪
- 时价比贪婪(价时比指的是价值与时间的比值)
实现如下:
def value_greedy(n, time):
'''价值贪婪算法'''
route = [] #存储需要抢夺的礼物下标
v_sort = sorted(enumerate(v), key=lambda x: x[1])
new_idx = [i[0] for i in v_sort]
new_v = [i[1] for i in v_sort]
new_t = [t[i] for i in new_idx]
while time >= new_t[0]:
idx = 0
while idx < n - 1 and time >= new_t[idx + 1]:
idx += 1
next_v = new_v.pop(idx)
next_t = new_t.pop(idx)
next_idx = new_idx.pop(idx)
time -= next_t
route.append(next_idx)
total_v = 0
for i in route:
total_v += v[i]
print("价值贪婪时:\n需要抢夺的礼物是如下:{},总价值为:{}".format(route, total_v))
def time_greedy(n, time):
'''时间贪婪算法'''
route = [] #存储需要抢夺的礼物下标
t_sort = sorted(enumerate(t), key=lambda x: x[1])
new_idx = [i[0] for i in t_sort]
new_t = [i[1] for i in t_sort]
new_v = [v[i] for i in new_idx]
while time >= new_t[0]:
idx = 0
while idx < n - 1 and time >= new_t[idx + 1]:
idx += 1
next_v = new_v.pop(idx)
next_t = new_t.pop(idx)
next_idx = new_idx.pop(idx)
time -= next_t
route.append(next_idx)
total_v = 0
for i in route:
total_v += v[i]
print("时间贪婪时:\n需要抢夺的礼物是如下:{},总价值为:{}".format(route, total_v))
def vt_greedy(n, time):
'''价时比贪婪算法'''
route = [] #存储需要抢夺的礼物下标
vt = [ i/j for i,j in zip(v, t)]
vt_sort = sorted(enumerate(vt), key=lambda x: x[1])
new_idx = [i[0] for i in vt_sort]
new_t = [t[i] for i in new_idx]
new_v = [v[i] for i in new_idx]
while time >= new_t[0]:
idx = 0
while idx < n - 1 and time >= new_t[idx + 1]:
idx += 1
next_v = new_v.pop(idx)
next_t = new_t.pop(idx)
next_idx = new_idx.pop(idx)
time -= next_t
route.append(next_idx)
total_v = 0
for i in route:
total_v += v[i]
print("价时比贪婪时:\n需要抢夺的礼物是如下:{},总价值为:{}".format(route, total_v))
if __name__ == "__main__":
#物件总数
n = int(input("请输入礼物总数:"))
#物件价值
v_str = input("请输入每件物品的价值:(逗号隔开) ")
v_list = v_str.split(",")
v = list(map(int, v_list))
# print(v)
#拿取物品耗时
t_str = input("请输入拿取每件物品的时间:(逗号隔开) ")
t_list = t_str.split(",")
t = list(map(int, t_list))
#背包的大小
C = int(input("请输入总时间:"))
value_greedy(n, C)
time_greedy(n, C)
vt_greedy(n,C)
动态规划算法
我仅实现了二维表法
实现如下:
import numpy as np
#0-1背包问题
def zero_one():
#物件总数
n = int(input("请输入物件总数:"))
#物件价值
v_str = input("请输入每件物品的价值:(逗号隔开) ")
v_list = v_str.split(",")
v = [0] + list(map(int, v_list))
print(v)
#物件质量
w_str = input("请输入每件物品的质量:(逗号隔开) ")
w_list = w_str.split(",")
w = [0] +list(map(int, w_list))
print(w)
#背包的大小
C = int(input("请输入背包大小:"))
m = np.zeros([n + 1,C + 1], dtype=np.int)
for i in range(1, n + 1):
m[i, 0] = 0
for W in range(C + 1):
m[0, W] = 0
for i in range(1, n + 1):
for W in range(1, C + 1):
if w[i] > W:
m[i, W] = m[i-1, W]
else:
m[i, W] = max(m[i-1, W], v[i] + m[i-1, W-w[i]])
print(m)
if __name__ == "__main__":
zero_one()
结果比较
我们用同一组数据进行对比:(即开头的文章里面的链接之中用的数据)
结果如下:
贪婪算法:
动态规划算法:
我们可以观察到,贪婪算法的最终结果的最大值为35,而动态规划算法的最大值可以达到40,所以贪婪算法不可以成为01背包问题的最优算法,而动态规划算法是更好的选择。