01,完全 背包问题的一维数组

来源:互联网 发布:淘宝返利机器人怎么做 编辑:程序博客网 时间:2024/06/05 18:33

(博主懒,就不写二位数组了,大家也可以百度到的)
先来说明背包问题:
有一堆已知重量(weight[])以及价值(value[])的物品,在每件物品只能拿一次的情况下,在a件物品中选取重量不超过j的最大价值
设置f[v]为能拿到v件的物品时对应的最大价值,即求f[a];
直接上核心代码(也就是状态方程):

    for (int i = 1;i < a;i++)     {        for (int v=j;v>0;v--)         {            if (v >= weight[i])            {                f[v] =                     f[v] > (f[v- weight[i]] + value[i])? f[v]: f[v- weight[i]] + value[i];            }        }    }

(敲黑板)
注意,第二个for (int v=j;v>0;v–) 是从v=j倒序开始更新f[j];
也就是说,当f[v]开始更新的时候,
f[v] = f[v] > (f[v- weight[i]] + value[i])? f[v]: f[v- weight[i]] + value[i];
此时的f[v]其实是跟上一个i-1的时候的f[v]去比较(上一个的f[v]是不能取到第i件物品的)。更新之后如果能取到第i个物品,那么就比较不取第i件物品跟取到第i件物品的价值。取大(f[v]全部初始化为0)
so,注意理解。f[v]是能取第i件以及之前所有物品的最大价值,每次的比较都是围绕能取第i件(含之前的物品)以及第i-1件(含之前的物品)的价值。
上面是01背包问题。下面是完全背包

for (int i = 1;i < a;i++)     {        for (int v=1;v<j;v++)         {            if (v >= weight[i])            {                f[v] =                     f[v] > (f[v- weight[i]] + value[i])? f[v]: f[v- weight[i]] + value[i];            }        }    }

注意,修改的仅仅是第二个for循环的顺序。由倒序改成顺序。
01背包中,为什么要倒序,因为每个背包只能拿一次。那么在每一次的i,v循环中,我们仅仅需要知道的是第i件物品能不能放下,能的话跟上一次的比较就可以。因为上一次循环的f[v]是在i-1件物品只能拿一次的情况下的最大值,倒序是为了仅跟上次的状态(i-1件物品)比较。

完全背包中相反,采用顺序。
举例,第i件物品重量是1,价值是value;
那么这个时候要先更新f[1],比较前i-1件物品的f[1]以及value;
然后到f[2],f[2]就应该max(前i件物品的f[2-1]+value,前i-1件物品的f[2-1])然后跟前i-1件物品的f[2]比较。
f[3]同理。一路推到f[v]。
完全背包比较的应该是:前i件物品的f[v-weight]+value,前i-1件物品的f[v-weight],前i-1件物品的f[v]这三者的比较。也就是当前状态,需要先推导出重量v之前的当前状态,才能得到最大值。这就是完全背包