标签:
有n件物品,第i件物品(I = 1,2,3…n)的价值是vi, 重量是wi,我们有一个能承重为m的背包,我们选择一些物品放入背包,显然放入背包的总重量不超过m。我们要求选择物品的总价值最大,请问如何选择?这里我们假设所有出现的数都是正整数。
优化?我们看一下这个递推式子核心就是f(i,j) = max(f(i – 1, j) , f(i-1,j - wi) + vi), 看一下f(i,*)只与f(i-1,*)相关,再仔细看看我们的第维j,只和更小的值相关,我们可以省掉一维i,然后倒着循环j,用旧的值更新新的值,这时f一部分是旧的值f(i-1,*),一部分是新的值f(i,*)。更具体地说小于j地是旧值,其余是新值。
核心伪代码:
1 f(0) = 0 2 f(1..m) = -∞ 3 for i = 1 to n do 4 for j = m downto wi do 5 f(j) = max(f(j), f(j - wi)) 6 endfor 7 endfor
所求结果是max{f(0..m)}
注意我们循环j只到wi,因为再小的j会导致我们无法选择第i件物品,这时我们直接使用不用第i件物品的旧值就好啦。简单吧?
那么现在,时间复杂度时不变的,空间复杂度降低O(m)了。
们尝试换一种状态表示? 我们令f(i,j)表示决定了前i件物品,总重量不超过j时能获得的最大价值。仔细想想递推式是不变的,那么初值呢?如果初值不变,f就没变化了……i= 0时,总重量时0,又因为0不超过任何整数,所以根据定义初值是f(0,*) = 0
那么最终结果呢?根据定义,最终结果是f(n,m)而没有必要再一串数里取最大了。可见即使递推式相同,初值不同也会定义不同的函数,请不要忽略初值的作用啊。同样我们可以优化掉第一维。
核心伪代码:
1 初值f(0..m) = 0 2 for i = 1 to n do 3 for j = m downto wi do 4 f(j) = max(f(j), f(j - wi)) 5 endfor 6 endfor
所求结果是f(m)
再换一种状态表示?刚才讲了,我们有重量和价值两个指标,那么我们令f(i,j)是决定了前i件物品,总价值恰好是j时的最小重量,那么经过类似的分析,我们可以写出这样的初值和递推式:
第1行,2个整数,N和W中间用空格隔开。N为物品的数量,W为背包的容量。(1 <= N <= 100,1 <= W <= 10000) 第2 - N + 1行,每行2个整数,Wi和Pi,分别是物品的体积和物品的价值。(1 <= Wi, Pi <= 10000)
输出可以容纳的最大价值。
3 6 2 5 3 8 4 9
14
1 def array(n): 2 a=[] 3 for i in range(n): 4 a.append(0) 5 return a 6 def max(x,y): 7 if x>y: 8 return x 9 else: 10 return y 11 12 line=input().split() 13 n=int(line[0]) 14 v=int(line[1]) 15 w=[0] 16 p=[0] 17 f=array(v+1) 18 for i in range(n): 19 line=input().split() 20 w.append(int(line[0])) 21 p.append(int(line[1])) 22 for i in range(1,n+1): 23 for j in range(v,w[i]-1,-1): 24 f[j]=max(f[j],f[j-w[i]]+p[i]) 25 print(f[v])
标签:
原文地址:http://www.cnblogs.com/nbalive2001/p/4774191.html