01背包(动态规划解法)

01背包(动态规划解法)

01背包是一个很经典的问题,题目如下:有n件物品和一个最多能装重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,问怎样装载能使背包里物品的价值最大。

这里我们用一组简单的数据来进行示例:假设背包最大容量为5

物品 重量 价值
物品0 1 15
物品1 2 20
物品2 3 25
物品3 4 30

它与普通背包的区别在于,每个物品要么放,要么不放,而普通背包是可以放一部分的,因而普通背包可以通过贪心算法求解,01背包却不行。我们先来看看最不用动脑的暴力解法,即遍历每一种装载的可能,n个物品都有放与不放两种情况,因此暴力的时间复杂度为O(2n),指数级的时间复杂度不是很理想,如果在竞赛题里基本上是不可能AC的,于是我们再用动态规划来求解:

1.确定dp数组含义

题目的主干是n件物品放进容量(可装重量)为W的背包的最大价值。所以定义一个二维数组dp,dp[i] [j]表示将前i件物品选择后放进容量为j的背包的最大价值,最终dp[n-1] [W]就是我们要求的最大价值(物品下标从0开始,所以n-1就已经是n件物品了)。

2.找出状态转移方程

状态转移方程就是前后状态之间的关系,有了这个方程我们就可以在遍历数组时通过前面的值推出当前的元素值。

对应到题目中,我们可以从两个方面来找,对于dp[i] [j],我们可以选择把第i+1个物品不放入背包,那么它也就等同于只有i个物品,那么dp[i] [j]=dp[i-1] [j];如果选择将第i+1个物品放入背包,那么就要先预留好第i+1个物品的位置,也就是先找到i个物品放入容量为当前背包容量减去第i+1个物品的重量的最大价值,然后加上第i+1个物品的价值,也就是dp[i] [j]=dp[i-1] [j-weight[i]]+value[i]。然后再在二者中取最大值即可。即:

dp[i] [j]=max(dp[i-1] [j],dp[i-1] [j-weight[i]]+value[i])

3.初始化

初始化主要是当i和j为零的时候给元素赋值,因为后面的元素值都要根据它们推出。

当i=0时,就是只有背包容量j大于等于第一件物品的重量weight[0]时,对应的元素值为value[0];否则为0。

当j=0时,即背包容量为0,那么什么也装不下,直接初始化为0。

i \ j 0 1 2 3 4 5
物品0 0 15 15 15 15 15
物品1 0
物品2 0
物品3 0
int dp[MAXN][MAXN]={0};//数组大小根据情况设置
for(int j=0;j<=W;j++){//i=0时,遍历所有的j给元素赋值
    if(j>=weight[0])
        dp[0][j]=value[0];
}

4.遍历

这一步就是遍历所有可能的i、j,通过第二步的状态转移方程更新dp数组的值,两个for循环即可实现:

for(int i=1;i
i \ j 0 1 2 3 4 5
物品0 0 15 15 15 15 15
物品1 0 15 20 35 35 35
物品2 0 15 20 35 40 45
物品3 0 15 20 35 40 45

最后返回dp[n-1] [W]即可。我们可以看到,动态规划求解的时间复杂度是O(nW),显然要优于暴力求解。

补充

在动态规划中,我们提到了滚动数组这个概念,运用滚动数组将空间复杂度从O(n)优化到了O(1),而这里也同样适用。我们通过状态转移方程可以发现,每一个元素值都是由上一行得来的,如果我们把上一行的内容拷贝到当前行,就可以把二维数组优化成一维数组。

那么新的数组dp[j]表示将全部n个元素选择放入容量为j的背包能得到的最大价值;新的状态转移方程为:

dp [j]=max(dp [j],dp[j-weight[i]]+value[i])

然后进行遍历:

for(int i=1;i=weight[i];j--){
        dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
    }
}

你可能会发现,内层遍历变成了倒序,这是为什么捏?

因为当我们用一维数组来遍历,由状态转移方程可知,需要当前元素值和更前面的某一个元素(dp[j-weight[i]]+value[i]),如果先序遍历,那么更前面的那个元素的值可能已经发生了改变,对应到实际操作中就是有物品被重复计入了;而如果采用后序遍历,就能保证前面的值依然是上一层的,没有被更新。

如果不明白可以将红字多看几遍,思考一下,或者代入数据实际操作一下就能发现问题所在。(有些数据可能得出的结果看不出问题,可以直接使用文章中的数据进行试验。)

你可能感兴趣的:(C++和算法,动态规划,算法)