首先是 01 背包问题:数组
假设有不少商品每件商品都会占必定体积 v[x, y, z] (x,y,z是指某种商品占有的体积) 同时每件商品价值 w[x, y ,z] (对应于v里的商品所对应的价值)也不彻底同样,咱们有两种选择我拿走或者不拿走,可是个人背包容量有限不能把全部商品全拿走,怎么办才能使得咱们取得商品总的价值最大。app
首先这是一个动态规划问题,好比设咱们取第n件商品的时候咱们已经算出来取前n件商品的最大价值是f(n),那么咱们在取第n+1件的时候要么取走要么不拿走,也就有两种状况 A状况 这一种状况表明咱们选择要第n+1件商品函数
A = f(n) + w[n+1]
B状况 咱们不要这一件商品。优化
B = f(n)
因此 f(n+1) = max(A, B)spa
咱们就这样从第一件一直判断到第n件就能解决 01背包问题code
代码以下:blog
while True: try: N, V = (int(i) for i in input().split()) #这个是用来存商品体积的 ls_v = [0] #这个是用来存商品价值的 ls_w = [0] #咱们创建一个 宽度是 背包容量加一高度是商品数量加一的列表 f = [[0 for i in range(V+1)] for i in range(N+1)] for i in range(N): v, w = (int(i) for i in input().split()) ls_v.append(v) ls_w.append(w) #这个是咱们遍历全部商品 for i in range(N+1): #这个是咱们从体积为零一直增大到体积为V for j in range(V+1): #若是这个商品比咱们的背包容量还大确定要舍弃掉所以它的最优解确定和它上一个解同样 if ls_v[i] > j: f[i][j] = f[i-1][j] else: #这两个分别表明咱们取这一件商品和不取这一件商品 A = f[i-1][j] #若是取这一件商品那么背包确定要被占据必定空间,而后价值也会增长这件商品的价值 B = f[i-1][j-ls_v[i]] + ls_w[i] f[i][j] = max(A, B) print(f[-1][-1]) except: break
这个我已经运行过确定能够用。递归
而后咱们能够对它进行优化,时间复杂度降不了了,可是空间复杂度能够减小。ip
优化代码以下:input
while True: try: N, V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def ZeroOnePack(cost, weight, n): for i in range(n, cost-1, -1): f[i] = max(f[i], f[i-cost]+weight) for i in range(N): v, w = (int(i) for i in input().split()) ZeroOnePack(v, w, V) print(f[-1]) except: break
接着是彻底背包问题:
彻底背包问题里 商品就不是每一个只能选一个了,他假设每种商品都有无限多个,最后也是如何选取才能使得价值最大。
while True: try: N, V = (int(i) for i in input().split()) s = [0 for i in range(V+1)] ls_v = [0] ls_w = [0] for i in range(N): v, w = (int(i) for i in input().split()) ls_v.append(v) ls_w.append(w) for i in range(N+1): for j in range(V+1): if ls_v[i] <= j: s[j] = max(s[j], s[j-ls_v[i]]+ls_w[i]) print(s[-1]) except: break
或者写成函数方程:
while True: try: N, V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def CompletePack(cost, weight, n): for i in range(cost, n+1): f[i] = max(f[i], f[i-cost]+weight) for i in range(N): v, w = (int(i) for i in input().split()) CompletePack(v, w, V) print(f[-1]) except: break
最后是多重背包问题:
多重背包问题就是商品都有必定数量,一样也是如何选取可以使得所选的组合价值最大。
这里有两种思路一种就是转换成01背包问题,好比一种商品 体积是 3 价值是 4 数量是 3就能转化成 三个体积是3价值是4的商品。
代码以下:
while True: try:
#N是有多少种商品,V是背包的体积 N,V = (int(i) for i in input().split()) ls_v = [0] ls_w = [0] S = [0 for i in range(V+1)] for i in range(N): v, w, s = (int(i) for i in input().split())
#咱们每次获得一种商品商品总数就加上该种商品的数量 N += s-1 ls_v += [v]*s ls_w += [w]*s for i in range(1, N+1): for j in range(V, 0, -1): if ls_v[i] <= j: S[j] = max(S[j], S[j-ls_v[i]]+ls_w[i]) print(S[-1]) except: break
还有一种是使用一种是分解成01背包问题和无限背包问题while True try:
N,V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def ZeroOnePack(cost, weight, n): for i in range(n, cost-1, -1): f[i] = max(f[i], f[i-cost]+weight) def CompletePack(cost, weight, n): for i in range(cost, n+1): f[i] = max(f[i], f[i-cost]+weight) def MultiplePack(cost, weight, amount, n):
‘’‘
这里当数量很大都超过背包容量和无限次也就没有区别了,反正背包又不能全装走,好比背包容量为5商品体积是2
可是有三件很明显背包装不完
’‘’ if cost * amount > n: CompletePack(cost, weight, n) else: #这里只是为了把商品数量拆开而已,你彻底能够把商品拆成一件一件的答案和咱们拆成2的k次方是同样的 k = 1 while k < amount: ZeroOnePack(k*cost, k*weight, n) amount -= k k *= 2 ZeroOnePack(amount*cost, amount*weight, n) for i in range(N): v, w, s = (int(i) for i in input().split()) #你也能够不判断直接调用MultiplePack结果亦同样只不过程序多走两部而已。 if s == 1: ZeroOnePack(v, w, V) else: MultiplePack(v,w, s, V) print(f[-1]) except: break
再就是有的会把它全部组合一块儿,好比有的商品能够取无限次有的有限次有的只能一次,作法和咱们上面写的代码彻底同样没有区别,无非多了个判断咱们调用哪个函数。
二维背包问题
二维背包问题就是背包不但有体积限制还有重量限制,其实和一维背包问题差不太多无非在创建元组时从原先的一维数组变成二维数组,所用的递归公式都差很少。f[v][m] = max(f[v][m], f[v-cost][m-mass] + worth)
while True: try: N, V, M = (int(i) for i in input().split()) f = [[0 for i in range(M+1)]for j in range(V+1)] def ZeroOnePack(cost, mass, worth, n, m): for i in range(n, cost-1, -1): for j in range(m, mass-1, -1): f[i][j] = max(f[i][j], f[i-cost][j-mass] + worth) for i in range(N): v, m, w = (int(i) for i in input().split()) ZeroOnePack(v, m, w, V, M) print(f[-1][-1]) except: break