最详细完全背包问题,小白也可以看懂,哦耶~

完全背包问题

问题描述

完全背包是在N种物品中选取若干件(同一种物品可多次选取)放在空间为V的背包里
第i种物品的体积是v,价值是w
求将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大
—————————————————————————————

问题分析

在这里插入图片描述

首先看上面这张图

左边的黄色纵行代表的是第n件物品
上面的蓝灰色横行代表的是第n件物品的体积和价值
右边的绿色横行代表的是背包容量的大小
—————————————————————————————

分析

由上一篇0-1背包可知,当前状态只与上一次的状态有关,也就是只需要用一个一维数组(dp[])储存上一次的状态即可。
dp数组的含义是之前物品选择的最优解,之前的物品都有不选与多选的情况
所以对于第i件物品来说,也有不选与多选两种情况


角度一:

先从背包的角度来看,背包体积的选择范围是从0~V,但是当背包体积小于物品体积的时候,这个物品就是不选的,数据跟之前的相同。所以背包体积的选择范围是从v[i] ~ V。
在背包体积是j的情况下,物品i有选与不选两种情况,对应以下代码:

dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);

这时候你有可能会问:不是物品还有多选的情况吗?为什么这里只有选与不选的情况呢?
因为咱是从前往后遍历的,也就是在背包体积为j的情况下,j之前的所有数据都是在这个物品选与不选中的最优解,所以到背包体积为j的之后,有可能之前这个物品已经选过多次了,或是一次都没选。这里的选与不选是针对一定体积背包来说的。


完整代码:

public class Main {

    int N;   //物品的数量为N
    int V;   //背包的容量为V
    int[] dp = new int[Integer.MAX_VALUE];

    public int completeBag1(int[] v, int[] w){
        for(int i = 1; i <= N; i++){
            for(int j = v[i]; j <= V; j++){
                    dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
            }
        }
        return dp[V];
    }
}


角度二:
咱再从物品的角度来说,每种物品都有不选与多选的情况

最外层循环确定物品是啥(i)
中间循环因为从前往后会破坏数据,所以从后往前,具体是如何破坏的,咱也在0-1背包中说过了。中间循环的目的是为了确定背包的体积(j)
最后一层循环是为了确定物品的个数,因为选的个数不能使个数 * 物品体积 > 背包体积,所以j - k * v[i] >= 0 (k)

所以dp[j]的值就应该在这k个物品放与不放中选择:
1.不放:就是dp[i]
2.放:这个背包得腾出k * v[i]的体积来放,同时价值增加了k * w[i]

dp[j] = Math.max(dp[j], dp[j - k * v[i]] + k * w[i]);

完整代码:

public class Main {

    int N;   //物品的数量为N
    int V;   //背包的容量为V
    int[] dp = new int[Integer.MAX_VALUE];

    //优化以后的代码
    public int CompleteBag2(int[] v, int[] w){

        for(int i = 1; i <= N; i++){
            for(int j = V; j <= v[i]; j--){
                for(int k = 0; j - k * v[i] >= 0; k++) {
                    dp[j] = Math.max(dp[j], dp[j - k * v[i]] + k * w[i]);
                }
            }
        }
        return dp[V];
    }
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值