class Solution(object):
def snap(self,var_w1,w2,price_):
price=0
n=len(var_w1)
if w2<=0:
return 0
for i in range (n):
if var_w1[i]<=w2:
price=max(price_[i]+self.snap(var_w1[i+1:],w2-var_w1[i],price_[i+1:]),price) #好像是没有加上去
# print("i={},price={}".format(i,price))
return price
import time
st=time.time()
w1_=[5,4,6,3];price_=[10,40,30,50]
# w1_=[1,2];price_=[2,1]
sol=Solution()
w2=10
print("递归的结果为:",sol.snap(w1_,w2,price_))
se=time.time()
print("递归的时间消耗:",se-st)
递归的结果为: 90
递归的时间消耗: 0.0
class Solution(object):
def __init__(self,w1,price,w2):
self.w1=w1
self.price=price
self.n=len(w1)
def snap(self,w2):
price=0
if w2<=0:
return 0
for i in range (self.n):
if self.w1[i]<=w2:
price=max(self.price[i]+self.snap(w2-self.w1[i]),price) #好像是没有加上去
return price
import time
st=time.time()
w1_=[5,4,6,3];price_=[10,40,30,50];w2=10
sol=Solution(w1_,price_,w2)
print("记忆化搜索结果为:",sol.snap(w2))
se=time.time()
print("记忆化所花费的时间为:",se-st)
记忆化搜索结果为: 150
记忆化所花费的时间为: 0.0
class Solution(object):
def __init__(self,w1,w2):
self.memo=((min(w1)* w2)+1) *[-1]
#因为memo的长度最长为:w1中存在的最小的重量* 背包的负重,考虑到 snap()方法中的self.memo[w2]为下标索引,故加一个1
def snap(self,var_w1,w2,price_):
price=0
n=len(var_w1)
if w2<=0:
return 0
if self.memo[w2]!=-1:
return self.memo[w2]
for i in range (n):
if var_w1[i]<=w2:
price=max(price_[i]+self.snap(var_w1[i+1:],w2-var_w1[i],price_[i+1:]),price) #好像是没有加上去
print("i={},price={}".format(i,price))
self.memo[w2]=price
return price
import time
st=time.time()
w1_=[1,2];price_=[2,1];w2=3
sol=Solution(w1_,w2)
print("记忆化搜索结果为:",sol.snap(w1_,w2,price_))
se=time.time()
print("记忆化所花费的时间为:",se-st)
i=0,price=1
i=0,price=3
i=1,price=3
记忆化搜索结果为: 3
记忆化所花费的时间为: 0.0
def rob1(nums):
res=0
for i in range (len(nums)):
res=max(res,nums[i]+rob1(nums[i+2:]))
return res
class Solution(object):
def __init__(self,w1,price,w2):
self.w1=w1
self.price=price
self.n=len(w1)
self.memo=((min(w1)* w2)+1) *[-1]
#因为memo的长度最长为:w1中存在的最小的重量* 背包的负重,考虑到 snap()方法中的self.memo[w2]为下标索引,故加一个1
def snap(self,w2):
if self.memo[w2]!=-1:
return self.memo[w2]
price=0
if w2<=0:
return 0
for i in range (self.n):
if self.w1[i]<=w2:
price=max(self.price[i]+self.snap(w2-self.w1[i]),price) #好像是没有加上去
self.memo[w2]=price
return price
import time
st=time.time()
w1_=[5,4,6,3];price_=[10,40,30,50];w2=10
sol=Solution(w1_,price_,w2)
print("记忆化搜索结果为:",sol.snap(w2))
se=time.time()
print("记忆化所花费的时间为:",se-st)
记忆化搜索结果为: 150
记忆化所花费的时间为: 0.0010187625885009766
class Solution(object):
def snap(self,w1,p,w):
'''Dp Cal'''
dp=[]#创建一个二维的表
for i in range (len(w1)+1):
dp.append([0]*(w+1))
for i in range (len(w1)):#纵向(1,3)
for j in range (w+1):#横向
if w1[i]<=j:
dp[i+1][j]=max(p[i]+dp[i][j-w1[i]],dp[i][j])
else:
dp[i+1][j]=dp[i][j]
j+=1
return dp
w1=[5,4,6,3]
p=[10,40,30,50]
w=10
sol=Solution()
sol.snap(w1,p,w)
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10],
[0, 0, 0, 0, 40, 40, 40, 40, 40, 50, 50],
[0, 0, 0, 0, 40, 40, 40, 40, 40, 50, 70],
[0, 0, 0, 50, 50, 50, 50, 90, 90, 90, 90]]
#Test :初始化一个二维的dp数组,存储着
w1=[3,2,1];w=5;dp=[]
for i in range (len(w1)+1):
dp.append([0]*w )
print(dp)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
class Solution(object):
def snap(self,w1,p,w):
'''Dp Cal'''
dp=[]#创建一个二维的表
keep=[]
item=[]
keep_w=w
for i in range (len(w1)+1):
dp.append([0]*(w+1))
keep.append([0]*(w+1))
for i in range (len(w1)):#纵向(1,3)
for j in range (w+1):#横向
if w1[i]<=j and p[i]+dp[i][j-w1[i]]>dp[i][j]:
#这里填大于或者大于等于都可以,因为肯定大于,最根本的原因是因为每件商品的价值不一样,如果都一样的话,以后再证明
dp[i+1][j]=p[i]+dp[i][j-w1[i]]
keep[i+1][j]=1
else:
dp[i+1][j]=dp[i][j]
keep[i+1][j]=0
j+=1
for i in range (len(w1),0,-1):
if keep [i][keep_w]==1:
item.append(i)
keep_w-=w1[i-1]
else:
pass
return dp[len(w1)][w],keep,item
w1=[5,4,6,3]
p=[10,40,30,50]
w=10
sol=Solution()
dp_max,keep,item=sol.snap(w1,p,w)
print("The Max Price is: {}\nThe item is: {}".format(dp_max,item))
The Max Price is: 90
The item is: [4, 2]
首先0-1背包问题是比较特殊的DP问题,要想用DP,需要证明两点:
1.证明不论物品的顺序如何,总有一条唯一的解。
2.DP中的最优解是当前的最优解,而不是全局的最优解,只有在最后的一行中分别代表着w=0…N的时候的全局最优解。
下面开始证明第一条:
1.不论物品的顺序如何,总有一条唯一的解
如上图所示,在递归树中只有一个唯一的线路,因为是拿取不放回,所以线路只有一条,当我们改变物品的顺序后,发现1+3和3+1是一样的,也就是说,正因为是拿取不放回,所以赋予了递归树的特性:最优路线只有一条。
如上图4所示,当我们加入一个id:4的物品,w=10的时候,如橙色的线路,也是只有一条解,也就是说存在两个物品重量一样价值一样的话,当w=7的时候,会有两条路线,分别是:1-3 / 1-4 ,我们这里现在不讨论最优解的个数与W总负重的关系了,我们现在讨论第二个问题,这个0-1背包问题为什么能够用到动态规划,我们好像从上面的图中没有看到重复解?
别急,我们将总负载量提高为W=20,这时候上面的递归树肯定会多几层,我们就分析下面的三层递归树:
我们从上图5可以看到当负载量W=20的时候,并且层数大于等于3的时候,我们能够得到重复子结构,这个时候我们想到的就是用动态规划了。
下面正式进入第二个问题的解释:
DP中的最优解是当前的最优解,而不是全局的最优解,只有在最后的一行中分别代表着w=0…N的时候的全局最优解。
上图:
当我们看到i=1行的时候,我们拿w=5来说,可以看到每迭代一轮,w=5的解并不是最优解,知道迭代完最后一个id的时候才能确定最优解的最终情况,值得一提的是最优解可能早就有了,但是最后一行的最优解是最具有表征力的。
还有就是牢记一点:画递归树的时候,要想W=无穷大的时候的情况再遍历,即W=N的时候,这样就不用考虑是否有尽头了。