题名为:0-1背包问题。
题目要求:
动态规划:
1.用动态规划法设计0-1背包问题的算法,并且对给定的加权数据进行验证。要求分析算法时间复杂性并且形成分析报告。
依次把每一件物品都放入背包,当背包可容纳值大于等于当前物品重量,与之前可容纳物品的总价值进行对比,如果超出容量,则不换,没有超出换。
创建一个value[i][j]数组,表示在面对第 i 件物品,且背包容量为 j 时所能获得的最大价值,
1)当j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿
Value[ i ][ j ] = value[ i-1 ][ j ]
2)当j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。如果拿,则value[ i ][ j ]=value[ i-1 ][ j-w[ i ] ] + v[ i ]
N 物品数量 可以自定义
C 书包能承受的重量 可以自定义
W 每个物品的重量 随机生成
V 每个物品的价值 随机生成
N C time
5 10 0.0000768
10 10 0.0001398
50 60 0.00222469999
100 150 0.00844489999
发现一个很有意思的现象,如果我们用原始的递归办法去做,即排列组合的方法去做时时间复杂度为O(2^N);
当V很大,N较小时,比如V=1000,N=6时,用递归只用计算2^6=64次,而动态规划就需要计算1000*6=6000次
所以说,算法没有绝对的好坏,关键要看应用的惨景
import time
import random
def bag(n, c, w, v):
value = [[0 for j in range(c + 1)] for i in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, c + 1):
if j < w[i - 1]:
value[i][j] = value[i - 1][j]
else:
value[i][j] = max(value[i - 1][j], value[i - 1][j - w[i - 1]] + v[i - 1])
# 背包总容量够放当前物体,取最大价值
return value
def show(n, c, w, value):
print('最大价值为:', value[n][c])
x = [0 for i in range(n)]
j = c
for i in range(n, 0, -1):
if value[i][j] > value[i - 1][j]:
x[i - 1] = 1
j -= w[i - 1]
print('背包中所装物品为:')
for i in range(n):
if x[i]:
print('第', i+1, '个,', end='')
if __name__=='__main__':
n=100 #物品数量
c=150 #书包能承受的重量
# w = [2, 2, 3, 1, 5, 2] #每个物品的重量
w = [random.randint(1,10) for i in range(n)] #每个物品的重量
v = [2, 3, 1, 5, 4, 3] #每个物品的价值
v = [random.randint(1,10) for i in range(n)] #每个物品的价值
t1 = time.perf_counter()
value = bag(n,c,w,v)
# print(value)
show(n, c, w, value)
t2 = time.perf_counter()
print()
print(t2-t1)
此算法要的就是价值最大,不需要考虑其他因素,又是达不到最优。
此算法要的是背包里重量最大,也许会有空间剩余。
此算法也到不到整体最优。
先创建一个类,把输入的列表转变类对象,带有三个参数。价值,重量,状态。
然后按照每个算法策略不同的要求,排好序,放入背包即可。
# 背包问题贪心算法-贪单位重量价值量
class Good:
def __init__(self, weight, value, status):
self.weight = weight
self.value = value
self.status = status # 0是未放入背包,1是已经放入背包
class Greedy(object):
def greedy(self, goods, W): # goods是物品的集合,W是背包的空闲重量
result = []
sum_weight = 0
ppp = 0
danjia= 0
goods.sort(key=lambda obj: obj.value / obj.weight, reverse=True)
for i in goods:
if sum_weight + i.weight <= W :
sum_weight = sum_weight + i.weight
ppp = ppp + i.value
danjia = danjia + i.value / i.weight
result.append(i.weight)
return result, sum_weight, ppp, danjia
if __name__ == '__main__':
#重量,价值,状态
goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
g = Greedy()
result, sum_weight,ppp,danjia = g.greedy(goods, 150)
print("--------------按照取最小重量贪心策略--------------")
print("最终总价格为:" + str(ppp))
print("最终总重量为:" + str(sum_weight))
print("最终总单位价值量为:" + str(danjia))
print("重量选取依次为:", end='')
print(result)
# 贪价格
class Good:
def __init__(self, weight, value, status):
self.weight = weight
self.value = value
self.status = status # 0是未放入背包,1是已经放入背包
class Greedy(object):
def greedy(self, goods, W): # goods是物品的集合,W是背包的空闲重量
result = []
sum_weight = 0
ppp=0
goods.sort(key=lambda obj: obj.value)
for i in goods:
if sum_weight + i.weight <= W :
sum_weight = sum_weight + i.weight
ppp = ppp + i.value
result.append(i.weight)
return result, sum_weight, ppp
if __name__ == '__main__':
# goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),]
#重量,价值,状态
goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
g = Greedy()
result, sum_weight, ppp= g.greedy(goods, 150)
print("--------------按照取最小重量贪心策略--------------")
print("最终总重量为:" + str(sum_weight))
print("最终价格为:" + str(ppp))
print("重量选取依次为:", end='')
print(result)
class Good:
def __init__(self, weight, value, status):
self.weight = weight
self.value = value
self.status = status # 0是未放入背包,1是已经放入背包
class Greedy(object):
def greedy(self, goods, W): # goods是物品的集合,W是背包的空闲重量
result = []
sum_weight = 0
goods.sort(key=lambda obj: obj.weight)
for i in goods:
if sum_weight + i.weight <= W :
sum_weight = sum_weight + i.weight
result.append(i.weight)
return result, sum_weight
if __name__ == '__main__':
# goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),]
#重量,价值,状态
goods = [Good(35, 10, 0), Good(30, 40, 0), Good(60, 30, 0), Good(50, 50, 0),
Good(40, 35, 0), Good(10, 40, 0), Good(25, 30, 0)]
g = Greedy()
result, sum_weight = g.greedy(goods, 150)
print("--------------按照取最小重量贪心策略--------------")
print("最终总重量为:" + str(sum_weight))
print("重量选取依次为:", end='')
print(result)
网上说贪心算法不能解决0-1背包问题,得不到最优解。因为它无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。事实上,在考虑0-1背包问题时,应比较选择该物品和不选择该物品所导致的最终方案,然后再作出最好选择。由此就导出许多互相重叠的子问题。这正是该问题可用动态规划算法求解的另一重要特征。