完全背包问题和0-1背包问题简单理解

0-1背包问题:

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

完全背包问题:

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

  可以看出,两种问题的不同是完全背包问题的物品可以无限用,虽然不同,但是他们的模板代码是非常相似。也正因为这样,造成了理解上的困难。

先贴出两种问题的代码:

0-1背包问题:
void dp(int *f, int *t, int *v, int M, int T)
{
    for (int i = 1; i <= M; i++)
    {
        for (int j = T; j >= t[i]; j--)
        {
            f[j] = max(f[j - t[i]] + v[i], f[j]);
        }
    }
}
完全背包:
void dp(int *f, int *t, int *v, int M, int T)
{
    for (int i = 1; i <= M; i++)
    {
        for (int j = t[i]; j <= T; j++)
        {
            f[j] = max(f[j - t[i]] + v[i], f[j]);
        }
    }
}

可以看到代码的不同之处就是 j 的遍历是正序还是逆序。下面解释一下:
0-1背包问题:特点:每种物品仅有一件,可以选择放或不放。
  根据状态转移方程:第 i 次决策取决于第 i - 1次决策。这是 j 逆序遍历的原因。
完全背包问题:特点:每种物品有无限件。
  但是,决策和0-1背包问题不一样:第 i 次的决策不一定取决于第 i -1 次。当第i件物品出现时,可能会对以前的状态造成影响。因为有可能第i件物品出现后,之前所确定的状态加以改变 再加上第i件物品放入会构造更好的解决方案。所以,之前的状态需要改变,故要正序遍历 j 值。

举个例子:

这里有两道OJ题目:
0-1背包问题:https://www.luogu.org/problemnew/show/P1048
完全背包问题:https://www.luogu.org/problemnew/show/P1616
就以题目中的数据为例:
  设总时间70,采药总数3。
  采药所需时间和价值分别为:71,100;  69, 1;  1, 2.

  • 0-1背包问题:第一次决策要选择69 1;第二次则在第一次的决策上选择1  2;我们不需要去改变第一次的选择。
  • 完全背包问题:第一次决策可以选69  1,且只能选择一株。然后,我们进行第二次决策选择,此时可以且只能再选择一株1  2,这样构造的最终结果为f[T] = 3
      那么,我们可不可以构造比f[T] = 3更大的解呢?此题当然有。就是第一次决策选择1  2;然后以后的决策都选择1  2;这样最终结果f[T] = 140。比 f[T] = 3大多了。
       由此可以看出,我们在得到最优解过程中,是在进行第二次决策时否定了第一次的决策,需要重新进行以前的决策。这就是V正序遍历的原因。

再解释这个正序遍历的代码意思:
   i 表示第几件物品;
   j 表示当前背包的容量;
   在遍历到每一个 i (即每个物品)时,都要正序重新遍历一遍 j (即背包容量),也就是说更新以前(上一件物品时)的 f[j]。正好符合完全背包问题的决策思想。

最后,如果理解有错误还请多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值