01背包 完全背包 状态转移方程及空间复杂度优化

01 背包

问题描述:有N件【每件只有一个】物品和一个容量为V 的背包。第i 件物品的费用是w[i],价值是v[i],求将哪些物品装入背包可使价值总和最大。

定义状态:即f[i][j]表示前i件物品恰放入一个容量为j 的背包可以获得的最大价值。

状态转移方程:

f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

时间和空间复杂度均为O(VN)。时间复杂度不能再优化了,空间复杂度可以优化为O(N)

for (int i = 1; i <= n; i++)
    for (int j = V; j >= 0; j--)
        f[j] = max(f[j], f[j - w[i]] + v[i]);

注意:1:j是逆序   https://blog.csdn.net/yandaoqiusheng/article/details/84929357

   2 w[i]和v[i]中是i

可以进行优化的原因:每次写入数据都是根据上一行的结果写入的,数组一维就够用了

其中的f[j]=max(f[j],f[j−w[i]]) 一句相当于转移方程f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]) ,因为现在的f[j−w[i]]就相当于原来的f[i−1][j−w[i]]。
注意上述代码中利用了滚动数组原理

完全背包:

问题描述:有N种【每种有无数个】物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。状态转移方程:

f[i][j]=max(f[i−1][j−k∗w[i]]+k∗v[i])∣0<=k∗w[i]<=j

注意:f[i−1],不是f[i]

状态转移方程含义:若k=0,f[i−1][j]即j费用全部取前i-1种物品;若k=1,f[i−1[j−w[i]]+v[i],即j-w[i]费用取前i-1种物品,w[i]费用取第i种物品。。。。。

优化为O(VN):

for (int i = 1; i <= n; i++)
    for (int j = w[i]; j <= V; j++)
      f(i,j)=
          f(i-1,j),如果不取第i件物品
          f(i,j-w(i))+v(i),如果取第i件物品

解释一下,为什么一位数组中,不用写k循环。[其他博客中均没有详细解释这一点,我这里用自己的话来理解下】

假设不考虑f(i-1,j),如果不取第i件物品】这种情况

j=w(i)时,表示此次取一件i物品,f(i,0)+v(i)表示加上一件第i件物品的值,得到f(i,w(i))

j=2*w(i)时,由于滚动数组,f(i,w(i))已经是上一次的f(i,w(i)),已经加了一次w[i],所以这次只需再加一件w[i]即可。

...............

多次循环后,其实就等同于二维数组中的k循环了

写成代码:

for (int i = 1; i <= n; i++)
    for (int j = w[i]; j <= V; j++)
        f[j] = max(f[j], f[j - w[i]] + v[i]);

f[j]表示放入N种物品获得的最大价值

注意:正序

参考文献1

背包9讲:https://blog.csdn.net/yandaoqiusheng/article/details/84782655

完全背包优化:https://blog.csdn.net/wumuzi520/article/details/7014830

猜你喜欢

转载自www.cnblogs.com/JohnTeslaaa/p/12571857.html
今日推荐