动态规划:0-1背包问题
前言
背包问题是一种经典的动态规划求解问题,本文主要以经典0-1背包问题为例,阐述动态规划思想,求解背包问题,希望能够帮助到大家
一、什么是0-1背包问题?
背包问题指的是,存在一系列物品w1,w2,…,wn,物品数量存在n个,其中每个物品对应的价值为v1,v2,…,vn;此时需要将其装入一个承载量为weight的背包中,由于背包是存在一定的承载量的,因此在保证背包的承载量的条件下,我们希望能够背包中物品总和价值最大,此时应该如何从若干物品中挑选合适的物品,且每件物品只存在0 1两种选择,即选择或者未选择。
二、什么是动态规划
动态规划是通过将复杂的大问题分解成若干个易求解的子问题,并将其子问题的最优解存储在状态变量中,从而减少计算复杂度。动态规划具体步骤可参考动态规划心得及步骤
三、利用动态规划解决0-1背包问题
步骤如下:
(1)确定状态变量的物理意义;对于0-1背包问题,我们设置dp[i][j]表示将前i个物品放入承载量为j的背包中能够得到的最大价值量。
这样设置状态变量的原因是因为,首先背包问题存在两个变量,即物品的重量和物品的价值,因此状态变量为一个二元变量;至于其实际物理意义,在后续讲解中会说明为什么要这样设置其物理意义。
(2)确定状态转移方程;状态转移方程常常是寻找dp[i][j]与dp[i-1][j-1]、dp[i][j-1]等之间的关系,具体要根据设置的状态变量物理含义来确定。
对于上述背包问题,dp[i][j]表示将前i个物品放入承载量为j的背包中能够得到的最大价值量。此时可知道,对于dp[i][j]来说,可分为两种情况;
一种情况为dp[i][j]得到的最大价值量并没有包含物品i,即将前i-1个物品放入承载量为j的背包的最大价值量dp[i-1][j]与前i个物品放入承载量为j的背包的最大价值量dp[i][j]相等,即这种情况下dp[i][j]=dp[i-1][j];
第二种情况为dp[i][j]得到的最大价值量包含物品i,此时dp[i][j]=dp[i-1][j-w[i]]+v[i],上述公式理解为将前i个物品放入承载量为j的背包中能够得到的最大价值量等效于将前i-1个物品放入承载量为j-w[i]的背包中的最大价值量+第i个物品的价值量。为了方便大家理解,可以想象先在承载量为j的背包中放入第i个物品,然后剩余j-w[i]的承载量放入前i-1个物品,其价值总和则为dp[i-1][j-w[i]]+v[i]。
由上述两种情况可知,由于需要保证dp[i][j]在整体情况下的最大值,所以
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])。
值得注意的是,当w[i]>j时,此时不存在第二种情况,即dp[i][j]=dp[i-1][j],因为此时无法将第i个物品放入承载量为j的背包中。
(3)确定初始条件;此时常常为dp[0][0]、dp[0][i];
对于背包问题来说,dp[0][i]表示为0个物品放入承载量为i的背包中的最大价值量,所以dp[0][i]=0;同样地,dp[i][0]=0
(4)确定输出条件;根据dp[i][j]的实际物理意义可知,要求n个物品在承载量为w的背包中的最大价值量,即dp[n][w],在程序中也可以写为dp[-1][-1]
上述背包问题python代码如下:
n = 4 #物品数量
weight = 10 #背包承载量
v = [6,3,5,4,6]#物品价格
w = [2,2,6,5,4]#物品重量
n = len(v)
dp = [[0 for _ in range(weight+1)] for _ in range(n+1)]#dp状态变量的定义
#初始状态的定义
dp[0][0] = 0
for i in range(n+1):
dp[i][0]=0
for i in range(weight+1):
dp[0][i]=0
#状态转移方程
for i in range(1,n+1):
for j in range(1,weight+1):
if j>=w[i-1]:#当第i个物品重量小于背包可承载量,即存在将第i个物品放入背包的情况
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i-1]]+v[i-1])
else:#当第i个物品重量大于背包可承载量,此时只存在第一种情况
dp[i][j] = dp[i-1][j]
print(dp[-1][-1])
本题输出结果为15
总结
提示:这里对文章进行总结:
本文主要讲述了如何利用动态规划解决0-1背包问题,并简要复习动态规划具体流程,代码书写步骤也是按照动态规划步骤进行书写,希望对大家能够有所帮助。